Розробка блоку "з цим товаром купують" 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Розробка блоку "з цим товаром купують" 1С-Бітрікс
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Розробка блоку "з цим товаром купують" 1С-Бітрікс

«З цим товаром купують» — блок, який показує товари, що реально придбавалися разом із поточним у рамках одного замовлення. Це не «схожі товари» і не «раніше переглянуті» — це статистика спільних покупок. Правильно реалізований блок збільшує середній чек, адже пропонує те, що дійсно потрібно покупцеві в контексті обраного товару.

Джерело даних: таблиці замовлень Бітрікс

Дані беремо з реальних замовлень. Ключові таблиці:

  • b_sale_order — замовлення (статус, дата, користувач).
  • b_sale_basket — позиції в замовленнях (товар, кількість, ціна).

Логіка: знаходимо всі замовлення, в яких було куплено товар A, потім дивимося, які інші товари зустрічалися в цих самих замовленнях. Чим частіше — тим вище в рекомендаціях.

SELECT
    b2.product_id                       AS recommended_id,
    COUNT(DISTINCT b2.order_id)         AS co_purchase_count
FROM b_sale_basket b1
JOIN b_sale_order o ON b1.order_id = o.id
    AND o.canceled = 'N'
    AND o.status_id NOT IN ('F')  -- виключаємо скасовані статуси
JOIN b_sale_basket b2 ON b1.order_id = b2.order_id
    AND b2.product_id != b1.product_id
    AND b2.product_id IS NOT NULL
WHERE
    b1.product_id = :productId
    AND o.date_insert >= DATE_SUB(NOW(), INTERVAL 90 DAY)
GROUP BY b2.product_id
HAVING co_purchase_count >= 3  -- мінімальний поріг для надійності
ORDER BY co_purchase_count DESC
LIMIT 20;

Обмеження вибірки 90 днями — щоб асортиментні зміни відображалися в рекомендаціях швидше.

Попередній розрахунок і кеш

Запускати цей SQL при кожному відкритті картки товару не можна — надто важко для активного каталогу. Попередньо розраховуємо для топ-N товарів і зберігаємо результат.

CREATE TABLE custom_co_purchases (
    product_id      INT NOT NULL,
    recommended_id  INT NOT NULL,
    score           INT NOT NULL,
    calculated_at   DATETIME DEFAULT NOW(),
    PRIMARY KEY (product_id, recommended_id),
    INDEX idx_product (product_id)
);

Агент Бітрікс запускається раз на добу в нічний час, перераховує таблицю для товарів, що продавалися за останні 90 днів.

// Агент у local/php_interface/init.php
function RecalcCoPurchasesAgent(): string {
    $topProducts = getTopSellingProducts(500); // топ-500 товарів
    foreach ($topProducts as $productId) {
        $recs = calcCoPurchases($productId);
        saveToCoPurchases($productId, $recs);
    }
    return 'RecalcCoPurchasesAgent();'; // агент продовжує
}

Компонент відображення

Створюємо компонент company:catalog.co_purchases у local/components/:

// component.php
if (!\Bitrix\Main\Loader::includeModule('iblock') || !\Bitrix\Main\Loader::includeModule('catalog')) {
    return;
}

$productId = (int)$arParams['PRODUCT_ID'];
$limit     = (int)($arParams['LIMIT'] ?? 8);

// Читаємо з кешу
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache(3600, "co_purchases_{$productId}_{$limit}", '/co_purchases')) {
    $arResult = $cache->getVars();
} elseif ($cache->startDataCache()) {
    $recommendedIds = getFromCoPurchasesTable($productId, $limit);
    $arResult       = getProductsByIds($recommendedIds);
    $cache->endDataCache($arResult);
}

$this->IncludeComponentTemplate();

Фільтрація та валідність рекомендацій

Перед відображенням фільтруємо рекомендовані товари:

function filterValidRecommendations(array $productIds): array {
    if (empty($productIds)) return [];

    // Лише активні товари з ненульовим залишком
    $filter = [
        'ID'     => $productIds,
        'ACTIVE' => 'Y',
        '>CATALOG_QUANTITY' => 0,
    ];

    $result = [];
    $res    = \CIBlockElement::GetList([], $filter, false, false, ['ID']);
    while ($row = $res->Fetch()) {
        $result[] = $row['ID'];
    }
    return $result;
}

Якщо у товару недостатньо спільних покупок (наприклад, новий товар) — показуємо товари з тієї самої категорії як fallback.

Холодний старт

Для нових товарів або магазинів з малою історією замовлень — використовуємо content-based fallback:

function getRecommendations(int $productId, int $limit): array {
    $coPurchases = getFromCoPurchasesTable($productId, $limit);

    if (count($coPurchases) >= $limit) {
        return $coPurchases;
    }

    // Доповнюємо товарами з тієї самої категорії
    $needed    = $limit - count($coPurchases);
    $exclude   = array_merge([$productId], $coPurchases);
    $categoryFill = getSameCategoryProducts($productId, $needed, $exclude);

    return array_merge($coPurchases, $categoryFill);
}

Відображення в кошику

Блок працює і в кошику — «до товарів у вашому кошику часто купують». Логіка: беремо всі товари з кошика, об'єднуємо їхні рекомендації, ранжуємо за сумарним score, виключаємо вже додані в кошик.

$basketItems = \Bitrix\Sale\Basket::loadItemsForFUser(\Bitrix\Sale\Fuser::getId());
$basketIds   = [];
foreach ($basketItems as $item) {
    $basketIds[] = $item->getProductId();
}

$allRecs = [];
foreach ($basketIds as $id) {
    $recs = getFromCoPurchasesTable($id, 20);
    foreach ($recs as $rec) {
        $allRecs[$rec['recommended_id']] = ($allRecs[$rec['recommended_id']] ?? 0) + $rec['score'];
    }
}

// Виключаємо товари з кошика
foreach ($basketIds as $id) unset($allRecs[$id]);
arsort($allRecs);
$topRecs = array_slice(array_keys($allRecs), 0, 8);

Терміни

Етап Термін
SQL розрахунку спільних покупок + таблиця 1–2 дні
Агент попереднього розрахунку 1–2 дні
Компонент із кешуванням та fallback 2–3 дні
Блок у кошику 1–2 дні
Тестування та тюнінг порогів 1–2 дні

Разом: 1–1.5 тижні.