{ "index": 358, "slug": "editorial-2018-01-field-bitrix-elements", "title": "Почему элемент Bitrix есть в админке, но пропадает из каталога", "excerpt": "ID после CIBlockElement::Add подтверждает запись, но не публичную видимость. Разбираем фильтры инфоблока, товарный слой, права и кеш по проверяемой цепочке.", "contentHtml": "
Скрипт импорта сообщает об успехе: CIBlockElement::Add вернул ID. В админке элемент открывается. В каталоге его нет. Пользователь получает пустой список или старую карточку, а команда начинает очищать весь кеш. Цена ошибки — повторная загрузка того же товара, дубли, потерянное время и отсутствие доказательства, на каком условии запись исчезла.
Тезис: успешная запись и публичная видимость — разные факты. Сначала подтвердите, что Bitrix сохранил элемент. Затем повторите условия публичной выборки. После этого проверьте товарный слой, права, маршрут и кеш. Если запись не проходит более ранний фильтр, поздние проверки не объяснят симптом.
\nАдминский список может показать неактивный элемент, запись с прошедшей датой публикации или элемент из другого раздела. Публичный компонент обычно добавляет ACTIVE, ACTIVE_DATE, раздел, свойства, доступность и собственные проектные условия. Поэтому фраза «элемент есть в админке» означает только, что одна административная выборка его нашла.
У записи есть несколько границ. CIBlockElement::Add создаёт элемент инфоблока. Свойства сохраняются рядом с ним, но их наличие не означает, что товар готов к покупке. Цена, остаток, тип товара и торговые предложения относятся к каталожному слою. Компонент каталога может затем отфильтровать результат ещё раз. Кеш влияет только после того, как данные уже проходят действующие условия.
Не ограничивайтесь ID. При ошибке Add возвращает ложное значение, а причина доступна через LAST_ERROR. Сохраните внешний идентификатор импорта, ID инфоблока, название операции и результат. Если код продолжает выполнение после неуспешной записи, последующий запрос может проверять старый или пустой ID и увести расследование в сторону.
Учебный фрагмент ниже показывает только форму проверки. Число инфоблока и идентификатор элемента условны. Код не доказывает, что конкретный проект использует именно такую схему импорта.
\n<?php\n\n$element = new CIBlockElement;\n$elementId = $element->Add($fields);\n\n\nif (!$elementId) {\n throw new RuntimeException(\n 'Element was not created: ' . $element->LAST_ERROR\n );\n}\n\n$check = CIBlockElement::GetList(\n [],\n [\n 'IBLOCK_ID' => 12,\n '=ID' => (int) $elementId,\n ],\n false,\n ['nTopCount' => 1],\n ['ID', 'IBLOCK_ID', 'NAME', 'CODE', 'ACTIVE',\n 'DATE_ACTIVE_FROM', 'DATE_ACTIVE_TO']\n);\n\n$row = $check->Fetch();\nif ($row === false) {\n throw new RuntimeException('Saved element cannot be read');\n}\nВ реальном вызове в первый аргумент Add передают заполненный массив полей и свойств. В примере он пуст намеренно: важна граница между результатом записи и контрольным чтением. Сохранённый ID ещё не отвечает на вопрос, попадёт ли элемент в каталог.
CIBlockElement::GetList возвращает элементы по переданному фильтру. Для минимальной пробы используйте тот же инфоблок, ID, ACTIVE => Y и ACTIVE_DATE => Y, которые применяет публичная выдача. Выбирайте только нужные поля. Если контрольный запрос с этими условиями пуст, ищите проблему в полях элемента, датах, инфоблоке или разделах, а не в шаблоне.
Если базовая выборка возвращает строку, это ещё не доказательство видимости карточки. Компонент может требовать конкретное свойство, принадлежность к разделу, заполненный символьный код, разрешение пользователя или собственный флаг публикации. Скопируйте фильтр компонента в диагностический запрос по частям. Не заменяйте его догадкой «наверняка нужен кеш».
\n| Симптом | Причина | Проверка | Действие |
|---|---|---|---|
| ID не получен | Ошибка обязательного поля, свойства или прав | Проверить результат Add и LAST_ERROR | Исправить входные данные; не проверять пустой ID в каталоге |
ID есть, базовый GetList пуст | ACTIVE, даты, инфоблок или ID не совпадают | Считать элемент без публичных условий и сравнить поля | Исправить запись или фильтр импорта |
| Базовый запрос есть, карточки нет | Раздел, свойство, права или фильтр компонента | Сравнить реальный фильтр компонента с контрольным | Устранить первое несовпадающее условие |
| Карточка есть, купить нельзя | Нет цены, остатка, связи SKU или доступности | Проверить товарную модель и параметры каталога отдельно | Заполнить товарный слой или изменить требование компонента |
| После исправления видна старая версия | Кеш, индекс или другой источник данных | Сначала повторить чтение в обход кеша и сравнить ключ | Точечно обновить нужный слой после подтверждения данных |
| В админке виден, у гостя нет | Права или условие показа для текущего пользователя | Повторить запрос с теми же правами, что у посетителя | Исправить доступ или явно принять ограниченную видимость |
В Bitrix элемент инфоблока хранит общие данные: имя, код, активность, раздел и свойства. Для каталога этого может быть мало. Простой товар, товар с торговыми предложениями и другие типы используют разные связи и состояния. Публичный код может отбрасывать элемент без корректной цены, доступного предложения или нужного остатка.
\nПроверяйте товарный слой отдельным запросом и в терминах версии проекта. Старый код может использовать CCatalogProduct, а новый — классы пространства \\Bitrix\\Catalog\\Product. Нельзя смешивать исправление видимости инфоблока с миграцией API: сначала установите, какой слой не проходит условие, затем выбирайте совместимый способ изменения.
Отрицательный путь важен. Если элемент не должен продаваться, не добавляйте цену и остаток только ради того, чтобы карточка появилась. В таком случае видимость и доступность — разные требования. Изменение товарных параметров может открыть покупку, скидки или уведомления, хотя исходная задача касалась только списка.
\nКеш может вернуть старую выборку, но он не исправит неактивный элемент, неверную дату или отсутствующую цену. Полная очистка также меняет поведение других страниц и создаёт лишнюю нагрузку. Если данные не проходят фильтр, после очистки результат останется пустым. Если данные корректны, нужен адресный способ инвалидирования с понятным ключом.
\nДля проверки разделите два чтения: контрольное чтение из источника и чтение через публичный путь. Если источник уже не проходит фильтр, остановитесь на данных. Если источник проходит, а публичный ответ старый, зафиксируйте ключ кеша, время формирования и слой, который его обслуживает. Не делайте вывод по одному обновлению браузера.
\nCIBlockElement::Add; при ошибке остановитесь и выведите LAST_ERROR.ACTIVE и ACTIVE_DATE; запишите, на каком условии строка исчезает.Эта схема не заменяет знание конфигурации конкретного инфоблока и компонента. У проекта могут быть дополнительные фильтры, торговые предложения, складские остатки, права, поиск или внешний индекс. Один GetList не воспроизводит автоматически весь путь страницы.
Учебный код использует условный ID 12 и не выполняет реальную запись. Не запускайте его в production без заполненных полей, проверки прав и понимания побочных эффектов. Не очищайте общий кеш и не повторяйте импорт, пока не установили идемпотентность операции. В журнале не сохраняйте токены и персональные данные.
Если нет доступа к фильтру компонента, правам пользователя или товарному слою, вывод должен быть ограниченным: «элемент читается по ID, но публичная причина не установлена». Это полезнее, чем неподтверждённое обвинение кеша.
\nДиагностика готова, когда другой инженер может пройти путь от внешнего ID до публичного запроса и увидеть результат каждой границы: запись создана, поля сохранены, базовый фильтр пройден, товарный слой соответствует типу, права совпадают, а кеш или индекс проверены последними. Для отрицательного сценария указано условие остановки и действие, которое не следует выполнять.
\nИсправление можно считать подтверждённым только после повторного запроса по исходному публичному маршруту и с исходными правами. Он должен вернуть ожидаемый элемент, а журнал должен объяснять, какое условие изменилось. Если видимость подтверждена только в админке, задача ещё не закрыта.
\nACTIVE, даты активности и выборку полей.