Разработка фильтрации по рейтингу и отзывам 1С-Битрикс
Вы ведёте каталог с десятками тысяч товаров и отзывов. Клиенты хотят отфильтровать товары с рейтингом от 4.5 звёзд или только те, у кого есть отзывы. Стандартный умный фильтр 1С-Битрикс не справляется — он оперирует только свойствами инфоблока и ценой, а рейтинг — вычисляемая величина, хранящаяся в сторонних таблицах (blog, vote, custom). Без правильной реализации каждый запрос с JOIN добавляет 0.5–1.5 секунд к времени загрузки страницы. Мы — команда с опытом коммерческой разработки более 5 лет, реализовали более 50 проектов, включая каталоги с тысячами товаров. UF-поля — проверенный метод, который даёт фильтрацию без JOIN и без переписывания стандартного компонента. Расскажем, как это работает на практике.
Почему умный фильтр не видит рейтинг?
Потому что он не знает про поля UF_RATING и UF_REVIEW_COUNT. Система фильтрации работает только со свойствами инфоблока, а UF-поля — это свойства других сущностей. Но если добавить эти UF-поля к элементу инфоблока (через ENTITY_ID='IBLOCK_ELEMENT'), умный фильтр начнёт их видеть и использовать. Это избавляет от необходимости переопределять компонент или писать кастомные запросы.
Как добавить UF-поля для фильтрации рейтинга?
Используем связку UF-поля + обработчик событий или агент. Это даёт высокую производительность (фильтрация без JOIN) и гибкость (фильтр по любому диапазону).
Структура UF-полей для рейтинга
// Создание UF-полей при установке
$userTypeManager = \Bitrix\Main\EventManager::getInstance();
// UF_RATING - средний рейтинг
\CUserTypeEntity::Add([
'ENTITY_ID' => 'IBLOCK_' . CATALOG_IBLOCK_ID . '_SECTION',
'FIELD_NAME' => 'UF_RATING',
'USER_TYPE_ID' => 'double',
'MANDATORY' => 'N',
'SHOW_FILTER' => 'S',
'SETTINGS' => ['PRECISION' => 1, 'MIN' => 0, 'MAX' => 5],
]);
// UF_REVIEW_COUNT - количество отзывов
\CUserTypeEntity::Add([
'ENTITY_ID' => 'IBLOCK_' . CATALOG_IBLOCK_ID . '_SECTION',
'FIELD_NAME' => 'UF_REVIEW_COUNT',
'USER_TYPE_ID' => 'integer',
'MANDATORY' => 'N',
'SHOW_FILTER' => 'S',
]);
Обновление рейтинга при добавлении отзыва
AddEventHandler('blog', 'OnAfterPostAdd', 'updateProductRating');
AddEventHandler('blog', 'OnAfterPostUpdate', 'updateProductRating');
function updateProductRating($id, $fields)
{
// Получение ID товара из связи с отзывом
$productId = getProductIdFromPost($id);
if (!$productId) return;
// Пересчёт рейтинга
$reviews = getProductReviews($productId);
$count = count($reviews);
$avg = $count > 0
? array_sum(array_column($reviews, 'rating')) / $count
: 0;
// Обновление UF-полей элемента
CIBlockElement::SetPropertyValues($productId, CATALOG_IBLOCK_ID, [
'UF_RATING' => round($avg, 1),
'UF_REVIEW_COUNT' => $count,
]);
}
Фильтрация по минимальному рейтингу
// Применение фильтра рейтинга
if (!empty($_GET['min_rating'])) {
$minRating = floatval($_GET['min_rating']);
if ($minRating >= 1 && $minRating <= 5) {
$arFilter['>=UF_RATING'] = $minRating;
}
}
// Фильтр "только с отзывами"
if (!empty($_GET['has_reviews'])) {
$arFilter['>UF_REVIEW_COUNT'] = 0;
}
UI: звёздный рейтинг-фильтр
$currentMinRating = floatval($_GET['min_rating'] ?? 0);
?>
<div class="filter-block filter-block--rating">
<h3 class="filter-block__title">Рейтинг</h3>
<div class="rating-filter">
<?php for ($stars = 5; $stars >= 1; $stars--): ?>
<label class="rating-option <?= $currentMinRating == $stars ? 'is-active' : '' ?>">
<input type="radio" name="min_rating"
value="<?= $stars ?>"
<?= $currentMinRating == $stars ? 'checked' : '' ?>>
<span class="stars">
<?php for ($i = 1; $i <= 5; $i++): ?>
<svg class="star <?= $i <= $stars ? 'star--filled' : 'star--empty' ?>"
viewBox="0 0 24 24" width="16" height="16">
<polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26"/>
</svg>
<?php endfor; ?>
<span class="stars-label">от <?= $stars ?></span>
</span>
</label>
<?php endfor; ?>
</div>
<label class="filter-toggle">
<input type="checkbox" name="has_reviews" value="1"
<?= !empty($_GET['has_reviews']) ? 'checked' : '' ?>>
<span>Только с отзывами</span>
</label>
</div>
<?php
Сортировка по рейтингу
Фильтр по рейтингу органично сочетается с сортировкой:
$sortField = htmlspecialchars($_GET['sort'] ?? 'SORT');
$sortOrder = in_array(strtoupper($_GET['order'] ?? 'ASC'), ['ASC', 'DESC'])
? strtoupper($_GET['order'])
: 'ASC';
$arSort = match ($sortField) {
'rating' => ['UF_RATING' => 'DESC'],
'reviews' => ['UF_REVIEW_COUNT' => 'DESC'],
'price' => ['CATALOG_PRICE_1' => $sortOrder],
default => ['SORT' => 'ASC'],
};
Почему UF-поля быстрее JOIN?
UF-поля хранятся в отдельных таблицах с индексами и не требуют вычислительных операций при фильтрации. В отличие от JOIN, где каждый запрос объединяет таблицы, фильтр по UF-полям выполняется за константное время. Сравните:
| Подход | Время фильтрации (15 000 товаров) | Сложность реализации | Гибкость настройки |
|---|---|---|---|
| UF-поля с индексом | 0.2 сек | Средняя | Высокая (любые диапазоны) |
| JOIN к кастомной таблице | 1.5 сек | Высокая | Средняя (только точное совпадение) |
| Стандартный умный фильтр | Невозможно | – | – |
Согласно документации 1С-Битрикс, UF-поля могут участвовать в фильтрации при установке SHOW_FILTER = 'S' (см. официальное руководство).
Пошаговая реализация фильтрации по рейтингу
- Создание UF-полей. Добавьте UF_RATING (double) и UF_REVIEW_COUNT (integer) с SHOW_FILTER='S'.
- Разработка обработчика событий. В обработчике OnAfterPostAdd пересчитывайте средний рейтинг и количество отзывов.
- Настройка фильтра в компоненте. Укажите параметры FILTER_NAME и используйте UF-поля в фильтре.
- UI-фильтр. Сверстайте звёздный интерфейс с радио-кнопками для минимального рейтинга.
- Сортировка. Добавьте опцию сортировки по UF_RATING и UF_REVIEW_COUNT.
Сравнение методов обновления рейтинга
| Метод | Производительность | Сложность | Когда использовать |
|---|---|---|---|
| Обработчик событий (OnAfterPostAdd) | Высокая (мгновенно) | Средняя | Отзывы публикуются сразу |
| Агент с периодичностью (каждые 30 мин) | Средняя (отложенно) | Низкая | Отзывы проходят модерацию |
| Ручной пересчёт | Низкая (только по запросу) | Низкая | Мало отзывов, тестирование |
Кейс: маркетплейс электроники
Наш клиент — интернет-магазин электроники с 15 000 товаров. Внедрили звёздный рейтинг-фильтр и сортировку по рейтингу. UF-поля обновляются через агент каждые 30 минут (не по событию, так как отзывы проходят модерацию). После модерации — ручной пересчёт через кнопку в административной панели. Результат: товары без отзывов (новинки) скрыты по умолчанию в фильтре, показываются при снятии галочки «Только с отзывами». Конверсия из фильтрованного каталога (рейтинг 4+) на 23% выше среднего. Проект сдан в срок, заказчик доволен — мы гарантируем надёжность и поддержку после запуска.
Типичные ошибки при реализации
- Забывают установить SHOW_FILTER='S' — без этого UF-поля не участвуют в фильтрации.
- Не индексируют UF-поля — на больших каталогах падает производительность.
- Используют точное совпадение вместо диапазона — рейтинг редко бывает целым числом.
- Не обновляют рейтинг при удалении отзыва — данные застаиваются.
Что входит в работу
- Создание UF-полей и настройка индексов.
- Разработка обработчика событий или агента для пересчёта рейтинга.
- Вёрстка звёздного UI-фильтра с адаптивом.
- Сортировка по рейтингу и отзывам.
- Оптимизация кэширования для высокой нагрузки.
- Документация и краткое обучение для администраторов.
Сроки и стоимость
Фильтр по UF-рейтингу с простым UI — от 1 рабочего дня. Полная реализация с пересчётом рейтинга, звёздным UI, сортировкой и агентом — 2–3 рабочих дня. Стоимость рассчитывается индивидуально после анализа вашего проекта.
Свяжитесь с нами для бесплатной оценки вашего проекта. Закажите разработку — получите консультацию по оптимальному решению для вашего каталога.
Подробнее о возможностях UF-полей читайте в официальной документации. А общую информацию о платформе — на Wikipedia.







