Поиск по каталогу (bitrix:catalog.search) дополнить свойствами (напр. поиск по Артикулу)

Контекст проблемы

При попытке настроить поиск по свойству инфоблока типа «Строка» (например, «Артикул») через стандартный чекбокс «Значения свойства участвуют в поиске» результат часто оказывается некорректным. Это связано с тем, что модуль поиска Bitrix не всегда учитывает значения свойств, требующих дополнительной обработки или связанных с API-генерируемыми данными.

Анализ причины

  1. Ограничение стандартного функционала:

    • Чекбокс «Значения свойства участвуют в поиске» работает только для свойств, сохраняемых в плоской структуре (например, *`ELEMENTPROPERTY`**).

    • Для свойств, связанных с API (напр., артикулы, генерируемые через \Bitrix\Iblock\Elements\*) или динамически вычисляемых, требуется ручная индексация.

  2. Событие BeforeIndex:

    • Позволяет модифицировать данные перед их записью в поисковый индекс.

    • Через него можно добавить значение свойства «Артикул» в поля TITLE или BODY индекса.

Решение: Кастомный обработчик для события BeforeIndex

Реализуйте логику принудительной индексации артикула, используя следующий код в файле /local/php_interface/init.php:

<?php
use Bitrix\Main\EventManager;

// Регистрация обработчика события BeforeIndex
EventManager::getInstance()->addEventHandler(
    'search',
    'BeforeIndex',
    ['SearchHandlers', 'modifySearchIndex']
);

class SearchHandlers 
{
    /**
     * Модифицирует данные поискового индекса для элементов каталога.
     * 
     * @param array $arFields — массив данных индексации.
     * @return array — обновленный массив.
     */
    public static function modifySearchIndex(array $arFields): array 
    {
        // ID инфоблока каталога (заменить на актуальный)
        $catalogIblockId = 2; 
        // Символьный код свойства "Артикул"
        $articleCode = 'VENDOR_CODE'; 

        // Проверка модуля и инфоблока
        if (
            $arFields['MODULE_ID'] !== 'iblock' 
            || (int)$arFields['PARAM2'] !== $catalogIblockId
        ) {
            return $arFields;
        }

        // Получение значения свойства "Артикул"
        $articleValue = self::getElementPropertyValue(
            $arFields['ITEM_ID'], 
            $articleCode, 
            $catalogIblockId
        );

        if ($articleValue) {
            // Добавление артикула в заголовок и тело индекса
            $arFields['TITLE'] .= " [{$articleValue}]";
            $arFields['BODY'] = "{$articleValue} " . $arFields['BODY'];
        }

        return $arFields;
    }

    /**
     * Возвращает значение свойства элемента.
     * 
     * @param int $elementId — ID элемента.
     * @param string $propCode — символьный код свойства.
     * @param int $iblockId — ID инфоблока.
     * @return string|null — значение свойства.
     */
    private static function getElementPropertyValue(int $elementId, string $propCode, int $iblockId): ?string 
    {
        \Bitrix\Main\Loader::includeModule('iblock');

        $property = \CIBlockElement::GetProperty(
            $iblockId,
            $elementId,
            [],
            ['CODE' => $propCode]
        )->Fetch();

        return $property['VALUE'] ?? null;
    }
}

Или

use \Bitrix\Main\EventManager;
$eventManagerInstance = EventManager::getInstance();
$eventManagerInstance->addEventHandler(
    "search",
    "BeforeIndex",
    [
        "Handlers",
        "beforeIndex"
    ]
);
class Handlers
{
 public static function beforeIndex($arFields)
    {
        if (!$arFields["MODULE_ID"] == "iblock" &amp;&amp; $arFields['PARAM2'] == CATALOG_IBLOCK_ID) {
            return $arFields;
        }

        \Bitrix\Main\Loader::includeModule('iblock');
        $product = \Bitrix\Iblock\Elements\ElementCatalogTable::getByPrimary($arFields['ITEM_ID'], [
            'select' => ['ID', 'SKU' => 'VENDOR_CODE.VALUE'],
        ])->fetch();
        $arFields['TITLE'] .= ' ['.$product['SKU'].']';
        return $arFields;
    }
}

Критические замечания

  1. Переиндексация:

    • После внедрения кода выполните полную переиндексацию.
  2. Оптимизация запросов:

    • Для инфоблоков с большим количеством элементов используйте кеширование.
  3. Обработка ошибок:

    • Опционально можно добавить проверку существования элемента и свойства:
if (!\CIBlockElement::GetByID($elementId)->Fetch()) {
    return null;
}

Заключение Предложенное решение обходит ограничения стандартного поиска Bitrix, гарантируя корректную индексацию свойств типа «Строка». Метод поддерживает гибкую настройку и может быть адаптирован для любых пользовательских свойств, включая артикулы, серийные номера и другие идентификаторы.