Rating and Review Filter Development for 1C-Bitrix
You run a catalog with tens of thousands of products and reviews. Clients want to filter products with a rating of 4.5 stars or higher, or only those that have reviews. The standard 1C-Bitrix smart filter cannot handle this — it only works with information block properties and price, whereas rating is a computed value stored in third-party tables (blog, vote, custom). Without proper implementation, each query with a JOIN adds 0.5–1.5 seconds to page load time. We are a team with over 5 years of commercial development experience, having implemented more than 50 projects, including catalogs with thousands of products. UF-fields are a proven method that provides filtering without JOINs and without rewriting the standard component. Let us show how it works in practice.
Why does the smart filter not see the rating?
Because it does not know about the UF_RATING and UF_REVIEW_COUNT fields. The filtering system only works with information block properties, while UF-fields are properties of other entities. However, if you add these UF-fields to the information block element (via ENTITY_ID='IBLOCK_ELEMENT'), the smart filter will start seeing and using them. This eliminates the need to override the component or write custom queries.
How to add UF-fields for rating filtering?
We use a combination of UF-fields plus an event handler or agent. This provides high performance (filtering without JOINs) and flexibility (filter by any range).
Structure of UF-fields for rating
// Создание 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',
]);
Update rating when a review is added
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,
]);
}
Filter by minimum rating
// Применение фильтра рейтинга
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: star rating filter
$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
Sort by rating
Rating filtering combines naturally with sorting:
$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'],
};
Why are UF-fields faster than JOIN?
UF-fields are stored in separate tables with indexes and do not require computational operations for filtering. Unlike JOINs, where each query merges tables, filtering by UF-fields executes in constant time. Compare:
| Approach | Filtering time (15,000 products) | Implementation complexity | Configuration flexibility |
|---|---|---|---|
| UF-fields with index | 0.2 sec | Medium | High (any ranges) |
| JOIN to custom table | 1.5 sec | High | Medium (exact match only) |
| Standard smart filter | Not possible | – | – |
According to the 1C-Bitrix official guide on user fields, UF-fields can participate in filtering when SHOW_FILTER = 'S' is set. See also the Wikipedia article on 1C-Bitrix for general platform information.
Step-by-step implementation of rating filtering
- Create UF-fields. Add UF_RATING (double) and UF_REVIEW_COUNT (integer) with SHOW_FILTER='S'.
- Develop an event handler. In the OnAfterPostAdd handler, recalculate the average rating and review count.
- Configure the filter in the component. Specify the FILTER_NAME parameter and use UF-fields in the filter.
- Build the UI filter. Create a star interface with radio buttons for minimum rating.
- Add sorting. Include sorting options by UF_RATING and UF_REVIEW_COUNT.
Comparison of rating update methods
| Method | Performance | Complexity | When to use |
|---|---|---|---|
| Event handler (OnAfterPostAdd) | High (instant) | Medium | Reviews are published immediately |
| Periodic agent (every 30 min) | Medium (deferred) | Low | Reviews go through moderation |
| Manual recalculation | Low (on demand) | Low | Few reviews, testing |
Case study: electronics marketplace
One of our clients is an electronics online store with 15,000 products. We implemented a star rating filter and sorting by rating. UF-fields are updated via an agent every 30 minutes (not by event, because reviews go through moderation). After moderation, manual recalculation via a button in the admin panel. Result: products without reviews (new items) are hidden by default in the filter, shown when the "Only with reviews" checkbox is unchecked. The conversion rate from the filtered catalog (rating 4+) is 23% higher than average. The project was delivered on time, the client is satisfied — we guarantee reliability and post-launch support.
Common implementation mistakes
- Forgetting to set SHOW_FILTER='S' — without this, UF-fields do not participate in filtering.
- Not indexing UF-fields — performance drops on large catalogs.
- Using exact match instead of range — rating is rarely an integer.
- Not updating the rating when a review is deleted — data becomes stale.
What is included in the work
- Creation of UF-fields and index setup.
- Development of an event handler or agent for rating recalculation.
- Frontend of a star UI filter with responsiveness.
- Sort by rating and reviews.
- Cache optimization for high load.
- Documentation and brief training for administrators.
- Access to code repository and deployment instructions.
- Post-launch support for 1 month.
Timeline and cost
A filter based on UF-fields with a simple UI — from 1 business day (starting at $200). Full implementation with rating recalculation, star UI, sorting, and an agent — 2–3 business days (typically $500–$800). Cost is calculated individually after analyzing your project.
Contact us for a free assessment of your project. Request development — get a consultation on the optimal solution for your catalog.
Learn more about the capabilities of UF-fields in the official 1C-Bitrix documentation. And general information about the platform on Wikipedia.







