Сортировка в компонентах Битрикс

Архитектура обработки параметров сортировки

  1. Инициализация контекста запроса Используем класс Bitrix\Main\Application для получения объекта запроса:

    $request = Application::getInstance()->getContext()->getRequest();
  2. Валидация входных параметров Определяем "белый" список допустимых значений для полей сортировки и направления:

    const SORT_NEW = 'ACTIVE_FROM';
    const SORT_POPULAR = 'SHOW_COUNTER';
    $allowedSorts = [SORT_NEW, SORT_POPULAR];
    $allowedOrders = ['ASC', 'DESC'];
    
    $currentSort = in_array($request->get('sort'), $allowedSorts, true) 
       ? $request->get('sort') 
       : SORT_NEW;
    
    $currentOrder = in_array(strtoupper($request->get('order')), $allowedOrders, true) 
       ? strtoupper($request->get('order')) 
       : 'DESC';

Генерация URL с сохранением параметров

Инкапсулируем логику формирования URL в отдельную функцию:

function generateSortUrl(string $sortType, string $currentSort, string $currentOrder): string {
    $params = $request->getQueryList()->toArray();
    $newOrder = ($sortType === $currentSort) 
        ? ($currentOrder === 'ASC' ? 'DESC' : 'ASC') 
        : 'DESC';

    $params['sort'] = $sortType;
    $params['order'] = $newOrder;

    return '?' . http_build_query($params);
}

// Пример использования:
$sortLinkNew = htmlspecialcharsbx(generateSortUrl(SORT_NEW, $currentSort, $currentOrder));

Интеграция с компонентом news.list

Передаем валидированные параметры в компонент через массив $arParams:

$APPLICATION->IncludeComponent(
    "bitrix:news.list",
    "",
    [
        "IBLOCK_ID" => $arParams["IBLOCK_ID"],
        "SORT_BY1" => $currentSort,
        "SORT_ORDER1" => $currentOrder,
        "FIELD_CODE" => ["SHOW_COUNTER", "SHOW_COUNTER_START"], // Для отображения метрик
        // ...
    ],
    $component
);

Верстка интерфейса сортировки

Вариант 1. Кнопочный интерфейс

<div class="sort-btns__box">
    <button 
        class="<?= ($currentSort === SORT_NEW) ? 'active' : '' ?><?= $currentOrder === 'ASC' ? ' up' : '' ?>"
        onclick="location.href='<?= $sortLinkNew ?>'">
        Новизне
        <? if ($currentSort === SORT_NEW): ?>
            <span class="sort-arrow"><?= $currentOrder === 'ASC' ? '↑' : '↓' ?></span>
        <? endif; ?>
    </button>
</div>

Вариант 2. Выпадающий список

<form action="<?= $APPLICATION->GetCurPage() ?>">
    <select name="catalog_sort" onchange="this.form.submit()">
        <option value="asc" <?= $currentOrder === 'ASC' ? 'selected' : '' ?>>По возрастанию</option>
        <option value="desc" <?= $currentOrder === 'DESC' ? 'selected' : '' ?>>По убыванию</option>
    </select>
</form>

Оптимизация и безопасность

  1. Экранирование выходных данных Всегда используем htmlspecialcharsbx() для предотвращения XSS:

    $sortLink = htmlspecialcharsbx(generateSortUrl(...));
  2. Обработка GET-параметров через URLSearchParams Для JavaScript-реализации:

    const url = new URL(window.location.href);
    url.searchParams.set('order', newOrder);
    window.location.href = url.toString();

Расширение функциональности

  • Метрики популярности Добавляем поля SHOW_COUNTER и SHOW_COUNTER_START в FIELD_CODE компонента для отслеживания статистики.

  • Кеширование запросов Реализуем механизм кеширования с использованием CPHPCache для снижения нагрузки на БД:

    $cache = new CPHPCache();
    if ($cache->InitCache($cacheTime, $cacheKey)) {
      $result = $cache->GetVars();
    } elseif ($cache->StartDataCache()) {
      // Выполнение тяжелых запросов
      $cache->EndDataCache($result);
    }

Данный подход обеспечивает:

  • Строгую валидацию входных параметров.

  • Гибкость при изменении логики сортировки.

  • Защиту от XSS и недопустимых значений.

  • Совместимость с компонентами Bitrix и стандартами разработки.


Update


Простая сортировка во включаемой области

Можно вывести, например, в header.

<? if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) {
    die();
}
/**
 * @global object $APPLICATION
 * @var array $arResult
 * @var array $arParams
 */

use Bitrix\Main\Application;

$request = Application::getInstance()->getContext()->getRequest();
$getOrder = $request->get("order");
?>
<form id="sortForm" action="<?=$APPLICATION->GetCurPage()?>">
    <div class="sorting">
        <span>Сортировать по:</span>
        <div class="select__box sorting-box custom-select">
            <select name="catalog_sort" onchange="submitFormSorting()">
                <option value="asc"<?= $getOrder === 'asc' ? ' selected' : '' ?>>Цена (по возрастанию)</option>
                <option value="desc"<?= $getOrder === 'desc' ? ' selected' : '' ?>>Цена (по убыванию)</option>
            </select>
        </div>
    </div>
</form>
<script>
    function submitFormSorting() {
        let form = document.getElementById('sortForm')
        let select = form.querySelector('select[name="catalog_sort"]')
        let selectedValue = select.value
        let baseUrl = form.action
        window.location.href = `${baseUrl}?sort=SCALED_PRICE_1&order=${selectedValue}`
    }
</script>

// Или с сохранением GET параметров

<script>
/**
 * Функция для изменения сортировки в каталоге (возрастанию / убыванию).
 */
function submitFormSorting() {
    const form = document.getElementById('sortForm');
    const select = form.querySelector('select[name="catalog_sort"]');
    const selectedValue = select.value;
    // Текущий URL.
    const url = new URL(window.location.href);
    // Обновляем параметр сортировки.
    if (selectedValue) {
        url.searchParams.set('order', selectedValue);
    } else {
        url.searchParams.delete('order');
    }
    window.location.href = url.toString();
}
</script>