Добавление товара в «Избранное» в 1С-Битрикс: пошаговое руководство

В 1С-Битрикс из коробки нет встроенной функциональности для «Избранного», однако её можно легко реализовать несколькими способами. В этой статье мы разберём разные подходы, предоставим варианты кода и разберёмся, как избежать дублирования товаров при добавлении.

Добавление товара в Избранное

1. Общие принципы реализации «Избранного»

Хранение данных об избранных товарах

  • Сессия или cookie. Простой способ для неавторизованных пользователей – хранить список избранных товаров в сессии или в cookie.
  • Профиль пользователя. Для авторизованных пользователей удобнее хранить «Избранное» в базе, привязанной к пользователю, чтобы «Избранное» сохранялось между сессиями.
  • Highload-блок (HL-блок). Продвинутый способ, который подойдёт, если вам требуется гибкая структура и вы планируете обрабатывать большие объёмы данных.

Проверка на дублирование

Необходимо убедиться, что при повторном нажатии кнопки «Добавить в избранное» один и тот же товар не добавляется вторично. Для этого обычно проверяют, есть ли уже ID товара в текущем списке «избранного».

Интеграция с интерфейсом

Можно использовать:

  • Классические формы и отправку запросов через PHP (стандартные POST/GET запросы).
  • Ajax-запросы через JavaScript (jQuery, fetch или XMLHttpRequest). Это часто удобнее для добавления товара «на лету» без перезагрузки страницы.

2. Пример реализации с сохранением в сессии (для неавторизованных пользователей)

2.1. Создание компонента или скрипта для добавления в избранное

Допустим, у вас есть кнопка «Добавить в избранное». Пусть её нажатие отправляет AJAX-запрос на сервер (в PHP-скрипт). Для наглядности сделаем отдельный файл ajax_favorite.php.

Шаг 1: Создадим AJAX-скрипт ajax_favorite.php


    <?php
    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

    // Проверяем, подключены ли необходимые модули (если необходимо)
    if(!\Bitrix\Main\Loader::includeModule("iblock")) {
        echo json_encode(["status" => "error", "message" => "Модуль iblock не подключен"]);
        die();
    }

    // Идентификатор товара, который хотим добавить
    $productId = (int)$_REQUEST["product_id"];

    // Стартуем сессию, если она не запущена
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }

    if (!isset($_SESSION["FAVORITE_PRODUCTS"])) {
        $_SESSION["FAVORITE_PRODUCTS"] = [];
    }

    // Проверка, есть ли уже такой товар в избранном
    if (!in_array($productId, $_SESSION["FAVORITE_PRODUCTS"])) {
        $_SESSION["FAVORITE_PRODUCTS"][] = $productId;
        echo json_encode(["status" => "success", "message" => "Товар добавлен в избранное"]);
    } else {
        echo json_encode(["status" => "warning", "message" => "Товар уже в избранном"]);
    }

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
    

Шаг 2: Добавим кнопку на сайте


    <button
      class="add-to-favorite"
      data-product-id="<?= $arItem['ID'] ?>"
    >
      Добавить в избранное
    </button>
    

Шаг 3: Реализуем AJAX-запрос через JavaScript


    <script>
    document.addEventListener('DOMContentLoaded', function() {
        const buttons = document.querySelectorAll('.add-to-favorite');

        buttons.forEach(function(button) {
            button.addEventListener('click', function() {
                const productId = this.getAttribute('data-product-id');

                fetch('/ajax_favorite.php?product_id=' + productId, {
                    method: 'GET'
                })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                })
                .catch(error => {
                    console.error('Ошибка:', error);
                });
            });
        });
    });
    </script>
    

Что происходит?

  • При клике на кнопку формируется GET-запрос вида /ajax_favorite.php?product_id=123.
  • На сервере товар проверяется на наличие в сессии (в массиве $_SESSION["FAVORITE_PRODUCTS"]).
  • Если товар отсутствует, он добавляется в массив и возвращается сообщение об успехе.
  • Если товар уже есть, возвращается предупреждение, что он уже добавлен.

Минусы этого подхода:

  • У неавторизованных пользователей «Избранное» хранится только до окончания сессии или до момента, пока пользователь не очистит куки, и не всегда удобно переносить эти данные на другой компьютер или другое устройство.

3. Хранение «Избранного» в базе (для авторизованных пользователей)

3.1. Использование пользовательских полей в пользователях

В 1С-Битрикс мы можем добавить пользовательское поле (User Field), например UF_FAVORITE_PRODUCTS, и сохранять туда массив ID товаров.

  • Заходим в админку: НастройкиПользователиПользовательские поляДобавить пользовательское поле.
  • Указываем там параметр Код поля (например, UF_FAVORITE_PRODUCTS) и тип «Привязка к элементам» или «Строка» (если нужна гибкость – можно хранить строкой в JSON-формате).

Пример записи данных в пользовательское поле (PHP):


    <?php
    // Проверяем модули
    \Bitrix\Main\Loader::includeModule("main");
    \Bitrix\Main\Loader::includeModule("iblock");

    // Получаем ID авторизованного пользователя
    global $USER;
    if (!$USER->IsAuthorized()) {
        die("Пользователь не авторизован!");
    }

    $userId = $USER->GetID();
    $productId = (int)$_REQUEST["product_id"];

    // Получаем данные пользователя
    $rsUser = CUser::GetByID($userId);
    $arUser = $rsUser->Fetch();

    // Предположим, что в UF_FAVORITE_PRODUCTS хранится массив ID
    $favoriteProducts = $arUser["UF_FAVORITE_PRODUCTS"];
    if (!is_array($favoriteProducts)) {
        $favoriteProducts = [];
    }

    // Проверка на дублирование
    if (!in_array($productId, $favoriteProducts)) {
        $favoriteProducts[] = $productId;

        // Обновляем данные пользователя
        $user = new CUser;
        $fields = [
            "UF_FAVORITE_PRODUCTS" => $favoriteProducts
        ];
        $user->Update($userId, $fields);

        if ($user->LAST_ERROR) {
            echo json_encode(["status" => "error", "message" => $user->LAST_ERROR]);
        } else {
            echo json_encode(["status" => "success", "message" => "Товар добавлен в избранное"]);
        }
    } else {
        echo json_encode(["status" => "warning", "message" => "Товар уже в избранном"]);
    }
    

Таким образом, список избранного «привязан» к учётной записи пользователя. Пользователь может авторизоваться с другого устройства – и увидит свой список избранного.

3.2. Хранение данных в Highload-блоке (HL-блоке)

Если вам нужен более гибкий способ управления «Избранным» (например, отдельная таблица с полями, датой добавления, статусом и т.д.), в 1С-Битрикс можно создать Highload-блок.

Шаг 1: Создаём HL-блок в административной части

  • Заходим в админку: НастройкиВысоконагруженные блоки (Highload-блоки)Добавить highload-блок.
  • Задаём название, например, FavoriteProducts.
  • Создаём поля:
    • UF_USER_ID (Тип: целое число, привязка к пользователю или просто ID)
    • UF_PRODUCT_ID (Тип: целое число, ID товара)
    • при необходимости другие поля.

Шаг 2: Пишем PHP-код для добавления в HL-блок


    <?php
    use Bitrix\Main\Loader;
    use Bitrix\Highloadblock as HL;
    use Bitrix\Main\Entity;

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
    Loader::includeModule("highloadblock");

    // ID вашего HL-блока, который вы создали в админке
    const HL_BLOCK_ID = 1; // замените 1 на ваш реальный ID

    // Функция для получения сущности HL-блока
    function getHlEntity($hlBlockId) {
        $hlblock = HL\HighloadBlockTable::getById($hlBlockId)->fetch();
        return HL\HighloadBlockTable::compileEntity($hlblock);
    }

    // Получаем сущность
    $entity = getHlEntity(HL_BLOCK_ID);
    $entityClass = $entity->getDataClass();

    // Получаем данные
    global $USER;
    if (!$USER->IsAuthorized()) {
        die(json_encode(["status" => "error", "message" => "Пользователь не авторизован"]));
    }

    $userId = $USER->GetID();
    $productId = (int)$_REQUEST["product_id"];

    // Проверяем, нет ли уже записи
    $res = $entityClass::getList([
        "select" => ["ID", "UF_USER_ID", "UF_PRODUCT_ID"],
        "filter" => ["=UF_USER_ID" => $userId, "=UF_PRODUCT_ID" => $productId],
        "limit" => 1,
    ]);
    if ($item = $res->fetch()) {
        // Нашли запись - значит товар уже в избранном
        echo json_encode(["status" => "warning", "message" => "Товар уже в избранном"]);
    } else {
        // Добавляем запись
        $result = $entityClass::add([
            "UF_USER_ID" => $userId,
            "UF_PRODUCT_ID" => $productId,
        ]);

        if ($result->isSuccess()) {
            echo json_encode(["status" => "success", "message" => "Товар добавлен в избранное"]);
        } else {
            $errors = $result->getErrorMessages();
            echo json_encode(["status" => "error", "message" => implode(", ", $errors)]);
        }
    }

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
    

Что делать с неавторизованными пользователями?

  • Можно сохранять данные в HL-блоке с использованием временного ключа (генерировать уникальный идентификатор, хранить его в cookie). При авторизации «переводить» избранное из временного ID в ID реального пользователя. Это более сложная схема, но гибкая и близкая к тому, как реализованы корзины в Bitrix.

4. Проверка на дублирование товаров

Как видно из примеров, проверка может осуществляться различными способами:

  • В сессии – с помощью in_array($productId, $_SESSION["FAVORITE_PRODUCTS"]).
  • В пользовательском поле – проверять через in_array($productId, $arUser["UF_FAVORITE_PRODUCTS"]).
  • В HL-блоке – запросом типа filter c =UF_USER_ID и =UF_PRODUCT_ID.

Важно убедиться, что перед добавлением вы всегда проверяете, присутствует ли уже этот товар в «Избранном», и если да – возвращаете сообщение пользователю, чтобы избежать дублей.

5. Вывод списка «Избранного» на сайте

5.1. Если используем сессию (для неавторизованных)


    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }

    $favoriteProducts = $_SESSION["FAVORITE_PRODUCTS"] ?? []; // если такого ключа нет, берём пустой массив
    if (!empty($favoriteProducts)) {
        // Предположим, товары лежат в инфоблоке с ID = 2, выведем их названия
        $arSelect = ["ID", "NAME", "DETAIL_PAGE_URL"];
        $arFilter = ["IBLOCK_ID" => 2, "ID" => $favoriteProducts];
        $res = CIBlockElement::GetList([], $arFilter, false, false, $arSelect);
        while ($ob = $res->GetNextElement()) {
            $arFields = $ob->GetFields();
            echo '<div>';
            echo '<a href="'.$arFields["DETAIL_PAGE_URL"].'">'.$arFields["NAME"].'</a>';
            echo '</div>';
        }
    } else {
        echo "У вас нет товаров в избранном";
    }
    

5.2. Если используем пользовательское поле


    global $USER;
    if ($USER->IsAuthorized()) {
        $userId = $USER->GetID();
        $rsUser = CUser::GetByID($userId);
        $arUser = $rsUser->Fetch();

        $favoriteProducts = $arUser["UF_FAVORITE_PRODUCTS"];
        if (!empty($favoriteProducts)) {
            $arSelect = ["ID", "NAME", "DETAIL_PAGE_URL"];
            $arFilter = ["IBLOCK_ID" => 2, "ID" => $favoriteProducts];
            $res = CIBlockElement::GetList([], $arFilter, false, false, $arSelect);
            while ($ob = $res->GetNextElement()) {
                $arFields = $ob->GetFields();
                echo '<div>';
                echo '<a href="'.$arFields["DETAIL_PAGE_URL"].'">'.$arFields["NAME"].'</a>';
                echo '</div>';
            }
        } else {
            echo "У вас нет товаров в избранном";
        }
    } else {
        echo "Авторизуйтесь, чтобы увидеть избранное";
    }
    

5.3. Если используем HL-блок


    use Bitrix\Main\Loader;
    use Bitrix\Highloadblock as HL;
    use Bitrix\Main\Entity;

    Loader::includeModule("highloadblock");
    Loader::includeModule("iblock");

    global $USER;
    if ($USER->IsAuthorized()) {
        $userId = $USER->GetID();

        $hlblockId = 1; // ваш ID
        $hlblock = HL\HighloadBlockTable::getById($hlblockId)->fetch();
        $entity = HL\HighloadBlockTable::compileEntity($hlblock);
        $entityClass = $entity->getDataClass();

        // Получаем все товары для данного пользователя
        $res = $entityClass::getList([
            "select" => ["ID", "UF_PRODUCT_ID"],
            "filter" => ["=UF_USER_ID" => $userId],
        ]);

        $productIds = [];
        while ($item = $res->fetch()) {
            $productIds[] = $item["UF_PRODUCT_ID"];
        }

        if (!empty($productIds)) {
            // Выбираем из инфоблока
            $arSelect = ["ID", "NAME", "DETAIL_PAGE_URL"];
            $arFilter = ["IBLOCK_ID" => 2, "ID" => $productIds];
            $dbElements = CIBlockElement::GetList([], $arFilter, false, false, $arSelect);
            while ($ob = $dbElements->GetNextElement()) {
                $arFields = $ob->GetFields();
                echo '<div>';
                echo '<a href="'.$arFields["DETAIL_PAGE_URL"].'">'.$arFields["NAME"].'</a>';
                echo '</div>';
            }
        } else {
            echo "У вас нет товаров в избранном";
        }
    } else {
        echo "Авторизуйтесь, чтобы увидеть избранное";
    }
    

6. Удаление из «Избранного»

Для реализации удаления из «Избранного» мы используем очень похожий подход, что и для добавления. Просто логика будет обратной: при получении ID товара мы проверяем, находится ли этот товар в избранном, и при наличии — удаляем.

6.1. Удаление из «Избранного» в сессии (неавторизованные пользователи)

Если вы храните ID товаров в $_SESSION["FAVORITE_PRODUCTS"], то удаление выглядит так:


    <?php
    // remove_favorite.php

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

    // Стартуем сессию, если вдруг она не запущена
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }

    $productId = (int)$_REQUEST["product_id"];

    // Проверяем, что массив существует
    if (!isset($_SESSION["FAVORITE_PRODUCTS"])) {
        $_SESSION["FAVORITE_PRODUCTS"] = [];
    }

    // Получаем индекс товара в массиве (если он там есть)
    $index = array_search($productId, $_SESSION["FAVORITE_PRODUCTS"]);
    if ($index !== false) {
        // Удаляем элемент из массива
        unset($_SESSION["FAVORITE_PRODUCTS"][$index]);
        // Сбрасываем ключи массива, чтобы индексы были последовательными
        $_SESSION["FAVORITE_PRODUCTS"] = array_values($_SESSION["FAVORITE_PRODUCTS"]);

        echo json_encode(["status" => "success", "message" => "Товар удалён из избранного"]);
    } else {
        echo json_encode(["status" => "warning", "message" => "Товар не найден в избранном"]);
    }

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
    

Примечание: для удобства можно сделать единый скрипт, который принимает действие action=add или action=remove. Но иногда проще и понятнее создавать два отдельных файла.

AJAX-запрос (JavaScript) для удаления может выглядеть так же, как и для добавления, только с другим URL (или с указанием другого параметра):


    <script>
    function removeFromFavorite(productId) {
        fetch('/remove_favorite.php?product_id=' + productId, {
            method: 'GET'
        })
        .then(response => response.json())
        .then(data => {
            alert(data.message);
        })
        .catch(error => console.error('Ошибка:', error));
    }
    </script>
    

6.2. Удаление из «Избранного» в пользовательском поле пользователя

Допустим, вы храните список ID товаров в пользовательском поле UF_FAVORITE_PRODUCTS (типа «Привязка к элементам» или «Строка»). Тогда удаление будет выглядеть так:


    <?php
    // remove_favorite_userfield.php

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
    \Bitrix\Main\Loader::includeModule("main");
    \Bitrix\Main\Loader::includeModule("iblock");

    global $USER;
    if (!$USER->IsAuthorized()) {
        echo json_encode(["status" => "error", "message" => "Необходима авторизация"]);
        die();
    }

    $userId = $USER->GetID();
    $productId = (int)$_REQUEST["product_id"];

    // Получаем текущие избранные товары
    $rsUser = CUser::GetByID($userId);
    $arUser = $rsUser->Fetch();
    $favoriteProducts = $arUser["UF_FAVORITE_PRODUCTS"];

    // Если пусто, сразу возвращаем предупреждение
    if (!is_array($favoriteProducts) || empty($favoriteProducts)) {
        echo json_encode(["status" => "warning", "message" => "У вас нет товаров в избранном"]);
        die();
    }

    // Ищем товар в списке
    $key = array_search($productId, $favoriteProducts);
    if ($key !== false) {
        unset($favoriteProducts[$key]);
        // Сбрасываем ключи, если требуется
        $favoriteProducts = array_values($favoriteProducts);

        $user = new CUser;
        $fields = ["UF_FAVORITE_PRODUCTS" => $favoriteProducts];
        $user->Update($userId, $fields);

        if ($user->LAST_ERROR) {
            echo json_encode(["status" => "error", "message" => $user->LAST_ERROR]);
        } else {
            echo json_encode(["status" => "success", "message" => "Товар удалён из избранного"]);
        }
    } else {
        echo json_encode(["status" => "warning", "message" => "Товар не найден в избранном"]);
    }

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
    

6.3. Удаление из «Избранного» в HL-блоке

При использовании Highload-блока мы храним каждую запись отдельно — «ID пользователя + ID товара». Удаление — это удаление соответствующей записи.


    <?php
    // remove_favorite_hl.php

    use Bitrix\Main\Loader;
    use Bitrix\Highloadblock as HL;
    use Bitrix\Main\Entity;

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

    Loader::includeModule("highloadblock");

    const HL_BLOCK_ID = 1; // ID вашего HL-блока

    // Получение класса сущности
    function getHlEntity($hlBlockId) {
        $hlblock = HL\HighloadBlockTable::getById($hlBlockId)->fetch();
        return HL\HighloadBlockTable::compileEntity($hlblock);
    }

    $entity = getHlEntity(HL_BLOCK_ID);
    $entityClass = $entity->getDataClass();

    global $USER;
    if (!$USER->IsAuthorized()) {
        echo json_encode(["status" => "error", "message" => "Необходима авторизация"]);
        die();
    }
    $userId = $USER->GetID();
    $productId = (int)$_REQUEST["product_id"];

    // Ищем запись
    $res = $entityClass::getList([
        "select" => ["ID"],
        "filter" => [
            "=UF_USER_ID" => $userId,
            "=UF_PRODUCT_ID" => $productId
        ],
        "limit" => 1
    ]);

    if ($row = $res->fetch()) {
        // Удаляем
        $deleteResult = $entityClass::delete($row["ID"]);
        if ($deleteResult->isSuccess()) {
            echo json_encode(["status" => "success", "message" => "Товар удалён из избранного"]);
        } else {
            $errors = $deleteResult->getErrorMessages();
            echo json_encode(["status" => "error", "message" => implode(", ", $errors)]);
        }
    } else {
        echo json_encode(["status" => "warning", "message" => "Товар не найден в избранном"]);
    }

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
    

7. Объединение «Избранного» при авторизации

Один из самых удобных сценариев — когда неавторизованный пользователь может добавлять товары в избранное (храним в сессии или cookies), а при авторизации вся эта информация «сливается» в ту структуру, что хранится у авторизованного пользователя (пользовательское поле / HL-блок).

7.1. Общая схема

  1. Пользователь (гость) переходит на сайт, добавляет товары в избранное. Эти ID хранятся в $_SESSION["FAVORITE_PRODUCTS"].
  2. Пользователь авторизуется. На событии авторизации (или сразу после авторизации) мы:
    • Берём товары из сессии.
    • Добавляем их в хранилище, закреплённое за пользователем (в HL-блоке или в UF_FAVORITE_PRODUCTS).
    • Очищаем сессию или же оставляем её для синхронизации.

7.2. Пример кода на событии OnAfterUserAuthorize

Bitrix позволяет «подцепиться» к событию авторизации пользователя: документация по событиям (если вдруг понадобятся детали). Ниже упрощённый пример:


    <?php
    // local/php_interface/init.php

    AddEventHandler("main", "OnAfterUserAuthorize", "MergeFavoriteAfterAuth");

    function MergeFavoriteAfterAuth($arParams)
    {
        global $USER;

        // Если авторизация прошла успешно:
        if ($arParams["user_fields"]["ID"] > 0) {
            $userId = $USER->GetID();

            // Берём товары из сессии
            if (session_status() == PHP_SESSION_NONE) {
                session_start();
            }

            if (!empty($_SESSION["FAVORITE_PRODUCTS"]) && is_array($_SESSION["FAVORITE_PRODUCTS"])) {
                $favoritesFromSession = $_SESSION["FAVORITE_PRODUCTS"];

                // --- Для примера с пользовательским полем ---
                $rsUser = CUser::GetByID($userId);
                $arUser = $rsUser->Fetch();
                $favoriteProductsUser = $arUser["UF_FAVORITE_PRODUCTS"];
                if (!is_array($favoriteProductsUser)) {
                    $favoriteProductsUser = [];
                }

                // Сольём массивы и удалим дубли
                $merged = array_unique(array_merge($favoriteProductsUser, $favoritesFromSession));

                // Сохраняем
                $user = new CUser;
                $fields = [
                    "UF_FAVORITE_PRODUCTS" => $merged
                ];
                $user->Update($userId, $fields);

                // Очищаем сессию или оставляем её, но обычно очищаем:
                unset($_SESSION["FAVORITE_PRODUCTS"]);
            }
        }
    }
    

Если у вас HL-блок, то, соответственно, вместо записи в UF_FAVORITE_PRODUCTS вам нужно будет сделать SELECT и INSERT через соответствующий highload-класс, аналогично тому, как это делается при добавлении.

Таким образом, если пользователь до авторизации добавил 3 товара, а в его профиле уже есть 2 товара, в результате будет 5 товаров без дублирования.

8. Отображение иконок и состояния «Избранного»

Часто на сайте рядом с товаром рисуют сердечко (иконку избранного). Если товар уже находится в избранном, сердечко делают «закрашенным» (активным). Есть несколько способов это отобразить:

8.1. Серверный рендеринг (PHP)

Вы на стороне сервера при формировании каталога или списка товаров проверяете, есть ли ID товара в списке избранного (сессия, пользовательское поле или HL-блок). Если есть — добавляете класс favorite-active, иначе favorite-inactive.


    <?php
    // Пример (упрощённый)
    // Пусть $arItem['ID'] — ID товара

    $isFavorite = false;
    if ($USER->IsAuthorized()) {
        // Проверяем в HL-блоке или пользовательском поле
        // или заранее подготовили массив $userFavorites
        $isFavorite = in_array($arItem['ID'], $userFavorites);
    } else {
        // Проверяем в сессии
        $isFavorite = in_array($arItem['ID'], $_SESSION["FAVORITE_PRODUCTS"]);
    }
    ?>

    <div class="product-item">
        <span class="product-name"><?= $arItem['NAME'] ?></span>
        <button
          class="favorite-btn <?= $isFavorite ? 'favorite-active' : 'favorite-inactive' ?>"
          data-product-id="<?= $arItem['ID'] ?>"
        >
          
          ♥
        </button>
    </div>
    

8.2. Клиентский рендеринг (JavaScript + AJAX)

  • При загрузке страницы можно по AJAX запросить список ID товаров в избранном и затем на клиенте динамически проставить класс «активный» для тех товаров, что вернутся в этом списке.
  • Это удобно, когда нужно быстро менять состояние без перезагрузки страницы.

Для большего удобства в UI можно использовать ту же кнопку, что и для добавления/удаления, просто при клике меняем класс и отправляем соответствующий AJAX-запрос («добавить» или «удалить»).

8.3. Пример клиентского подхода


    <script>
    document.addEventListener("DOMContentLoaded", function() {
        // Предположим, что у нас есть глобальный массив productIDs
        // со всеми ID товаров на странице

        // 1) Запрашиваем у сервера текущие избранные товары
        fetch('/ajax_get_favorites.php')
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    const favoriteList = data.favorites; // массив ID товаров в избранном
                    // 2) Ставим нужные классы
                    favoriteList.forEach(function(favId) {
                        let btn = document.querySelector(`.favorite-btn[data-product-id="${favId}"]`);
                        if (btn) {
                            btn.classList.remove('favorite-inactive');
                            btn.classList.add('favorite-active');
                        }
                    });
                }
            });
    });
    </script>
    

А в ajax_get_favorites.php мы возвращаем список избранных товаров для текущего пользователя (либо из сессии, либо из БД).

9. Оптимизация

Когда проект растёт, вопросов с избранным может стать много. Что учесть:

9.1. Использование HL-блоков

При большом количестве пользователей и товаров лучше хранить «Избранное» в HL-блоке:

  • Можно индексировать поля UF_USER_ID и UF_PRODUCT_ID.
  • Делать выборки по фильтру гораздо быстрее, чем в обычных пользовательских полях, если данных очень много.

9.2. Кеширование

  • Если у вас есть постоянные запросы на вывод «Избранного», можно кешировать результаты — например, сохранять итоговый список товаров для конкретного пользователя. Это особенно актуально, если пользователь редко меняет «Избранное», а просмотров страниц у него много.
  • В Bitrix используется механизм компонентного кеширования или статического кеширования с помощью класса CPHPCache.

9.3. Прочие моменты

  • При больших объёмах данных желательно оптимизировать сами SQL-запросы (например, не вызывать CIBlockElement::GetList для каждого товара, а сразу забирать их пакетно).
  • Не хранить лишние данные в сессии (только ID товаров), чтобы не перегружать её.

Итог

Функциональность «Избранного» можно расширять и дополнять по мере роста вашего проекта. Основные «фишки» для продвинутого использования:

  • Удаление — аналогично добавлению, только выполняется unset в массиве (сессия, пользовательское поле) или delete в HL-блоке.
  • Объединение «Избранного» — переносим данные из гостевой сессии в профиль пользователя при авторизации с помощью события OnAfterUserAuthorize.
  • Отображение иконок — показываем пользователю статус «в избранном / не в избранном» по данным с сервера или через AJAX.
  • Оптимизация — используем HL-блоки, индексы, кеширование и пакеты запросов при больших объёмах.

Таким образом, вы можете обеспечить удобную работу пользователям, избежать дублирования товаров и сохранить высокую производительность сайта.

7. Заключение

Функциональность «Избранного» в 1С-Битрикс можно реализовать разными способами. Самый простой – хранить избранное в сессии (или cookie) для неавторизованных пользователей. Более надёжный способ – хранить данные в базе, связанной с пользователем. Если проект крупный и нужно расширенное управление, то идеальный вариант – Highload-блок, позволяющий гибко хранить данные и обрабатывать их при большом трафике.

Главное во всех вариантах – не забывать проверять, не добавлен ли товар уже в избранное. Это поможет избежать дублей и сохранить удобство для пользователей.

Используйте подход, который подходит под задачи вашего проекта, и не бойтесь комбинировать их (например, гостевое избранное в сессии + перенос в базу после авторизации). Благодаря гибкой структуре 1С-Битрикс вы сможете настроить систему под любые нужды и обеспечить пользователям удобный функционал для сохранения любимых товаров.

Теги:  Избранное, добавление товара, сессия, cookie, пользовательское поле, Highload-блок, PHP, JavaScript, AJAX

Стоимость услуг по разработке и сопровождению сайтов на 1C-Битрикс

Техническая поддержка

выполняется с сайтами на основе любых CMS

от 5 000 рублей
Оптимизация производительности действующих интернет-проектов, наполнение и сопровождение, полная техническая поддержка и продвижение в поисковых сетях.

* стоимость зависит от объема и сложности выполняемых работ, используемой CMS.

Перенос сайтов на «1С-Битрикс»

сайты на платформе «1С-Битрикс» — это удобство, надежность и высокая посещаемость

от 12 000 рублей
Перенос сайтов с любых CMS и статичных страниц на платформу «1С-Битрикс», с учетом дизайна, верстки и урл-адресов. С сохранением всей информации и структуры сайта.

* зависит от объема выполняемых работ.

Лендинг

от 3 дней

от 25 000 рублей

Разработка одностраничного сайта на платформе Битрикс

* стоимость зависит от наличия верстки, использования готового решения и т.д.