Меню

Вывести торговые предложения (SKU) как простые товары в каталоге, с учетом раздела.

Просмотров: 322

Задача: Отобразить SKU товаров в каталоге как простые товары, учитывая текущий раздел. Необходимо вывести все торговые предложения (варианты, комплектации) для товаров, находящихся в текущем разделе каталога.

Получение ID инфоблока торговых предложений зная ID инфоблока каталога

Для начала нужно получить ID инфоблока с торговыми предложениями. В файле section.php комплексного шаблона каталога добавьте следующий код:

$skuIblockInfo = \Bitrix\Catalog\CatalogIblockTable::getList(array(
    'filter' => [
        'PRODUCT_IBLOCK_ID' => $arParams['IBLOCK_ID']
    ],
    'select' => [
            'IBLOCK_ID' // нам нужен только ID. Можете дополнительные поля если нужны
    ]
))->fetch();

В результате в переменной $skuIblockInfo['IBLOCK_ID'] будет храниться ID инфоблока с торговыми предложениями. Если параметр 'select' не указывать, вы получите дополнительную информацию:

Array
(
    [IBLOCK_ID] => 3
    [YANDEX_EXPORT] => N
    [SUBSCRIPTION] => N
    [VAT_ID] => 0
    [PRODUCT_IBLOCK_ID] => 2
    [SKU_PROPERTY_ID] => 19
)

В большинстве магазинов используется один инфоблок каталога и один связанный с ним инфоблок предложений. В таком случае нет необходимости использовать CatalogIblockTable::getList — достаточно посмотреть ID SKU инфоблока в админке и использовать его.

Я предлагаю универсальный подход, который будет полезен, если у вас много инфоблоков каталога (и, соответственно, много инфоблоков с предложениями), но вы используете один шаблон комплексного каталога для всех.

Получаем текущий раздел и ID торговых предложений по ID элементов раздела

  • Получение информации об инфоблоке SKU. Используем метод Bitrix\Iblock\IblockTable::getList, чтобы получить тип инфоблока, его ID и путь к детальной странице элемента.
  • Получение ID текущего раздела. Сначала получаем ID текущего раздела с помощью CIBlockFindTools::GetSectionID.
  • Получение ID элементов текущего раздела. Используем метод Bitrix\Iblock\ElementTable::getList, чтобы получить ID всех товаров в текущем разделе.
  • Получение торговых предложений. Для каждого элемента текущего раздела используем метод CCatalogSku::getOffersList, чтобы получить информацию о торговых предложениях и собрать их ID в массив $allOfferIds.
  • Передача массива в глобальный фильтр. Применяем его к компоненту bitrix:catalog.section и заполняем параметры для работы с инфоблоком торговых предложений.

Привожу весь код с комментариями:

// Получаем ID инфоблока SKU принадлежащего инфоблоку каталога
$skuIblockInfo = \Bitrix\Catalog\CatalogIblockTable::getList(array(
    'filter' => [
        'PRODUCT_IBLOCK_ID' => $arParams['IBLOCK_ID']
    ],
    'select' => [
        'IBLOCK_ID' // нам нужен только ID
    ],
    'cache' => [
        'ttl' => $arParams["CACHE_TIME"]
    ]
))->fetch();


// Получаем информацию об инфоблоке предложений
$resSkuIblock = Bitrix\Iblock\IblockTable::getList([
    'filter' => [
        'ID' => $skuIblockInfo['IBLOCK_ID']
    ],
    'select' => [
        '*' // Можно отобрать только нужные поля
    ],
    'cache' => [
        'ttl' => $arParams["CACHE_TIME"]
    ]
])->Fetch();


// Получаем ID текущего раздела
$currentSectionId = CIBlockFindTools::GetSectionID(
    $arResult['VARIABLES']['SECTION_ID'],
    $arResult['VARIABLES']['SECTION_CODE'],
    [
        'IBLOCK_ID' => $arParams['IBLOCK_ID']
    ]
);

// Получение ID элементов текущего раздела
$listElements = Bitrix\Iblock\ElementTable::getList([
    'filter' => [
        'IBLOCK_ID' => $arParams['IBLOCK_ID'],
        'IBLOCK_SECTION_ID' => $currentSectionId
    ],
    'select' => ['ID'],
    'cache' => [
        'ttl' => $arParams["CACHE_TIME"]
    ]
])->fetchAll();


// Проходим по каждому элементу
$allOfferIds = [];
foreach ($listElements as $element) {
    // Получаем предложения (SKU) для текущего элемента
    $offers = CCatalogSku::getOffersList($element['ID']);
    // Перебираем все предложения
    foreach ($offers as $offerGroup) {
        foreach ($offerGroup as $offer) {
            // Собираем только ID предложений
            $allOfferIds[] = $offer['ID'];
        }
    }
}

// Передача в глобальный фильтр
$GLOBALS[$arParams["FILTER_NAME"]] = [
    'ID' => $allOfferIds,
];

$intSectionID = $APPLICATION->IncludeComponent(
    "bitrix:catalog.section",
    "",
    [
        "IBLOCK_TYPE" => $resSkuIblock["IBLOCK_TYPE_ID"],
        "IBLOCK_ID" => $resSkuIblock["ID"], // или $skuIblockInfo['IBLOCK_ID']
        "FILTER_NAME" => $arParams["FILTER_NAME"],
        "SECTION_ID" => '',
        "SECTION_CODE" => '',
        "SECTION_URL" => '',
        "DETAIL_URL" => $resSkuIblock['DETAIL_PAGE_URL'],
        "SHOW_ALL_WO_SECTION" => "Y",
        // ....
        // Остальные настройки bitrix:catalog.section
        // ....
    ],
    $component
);
Михаил Базаров:
Лучше всего вынести всю описанную логику в отдельный компонент со своим классом и просто подключить в section.php

Чтобы сделать класс (например подключаемый из /vendor).
Код
<?php
namespace Ваш\namespace\если делаем модулем;

use Bitrix\Catalog\CatalogIblockTable;
use Bitrix\Iblock\IblockTable;
use Bitrix\Iblock\ElementTable;
use CCatalogSku;
use Bitrix\Iblock\SectionTable;

class IblockDataFetcher // или наследуемся от CBitrixComponent если делаем свой компонент
{
    protected $iblockId;
    protected $cacheTime;

    public function __construct($iblockId, $cacheTime)
    {
        $this->iblockId = $iblockId;
        $this->cacheTime = $cacheTime;
    }

    // Получить ID инфоблока SKU, принадлежащего каталогу
    public function getSkuIblockId()
    {
        $result = CatalogIblockTable::getList([
            'filter' => ['PRODUCT_IBLOCK_ID' => $this->iblockId],
            'select' => ['IBLOCK_ID'],
            'cache' => ['ttl' => $this->cacheTime],
        ])->fetch();

        return $result ? $result['IBLOCK_ID'] : null;
    }

    // Получить информацию об инфоблоке по ID
    public function getIblockInfo($iblockId)
    {
        return IblockTable::getList([
            'filter' => ['ID' => $iblockId],
            'select' => ['*'], // Можно урезать
            'cache' => ['ttl' => $this->cacheTime],
        ])->fetch();
    }

    // Получить текущий раздел
    public function getCurrentSectionId($sectionVariable)
    {
        return CIBlockFindTools::GetSectionID(
            $sectionVariable['SECTION_ID'],
            $sectionVariable['SECTION_CODE'],
            ['IBLOCK_ID' => $this->iblockId]
        );
    }

    // Получить список элементов текущего раздела
    public function getElementsInSection($sectionId)
    {
        return ElementTable::getList([
            'filter' => [
                'IBLOCK_ID' => $this->iblockId,
                'IBLOCK_SECTION_ID' => $sectionId,
            ],
            'select' => ['ID'],
            'cache' => ['ttl' => $this->cacheTime],
        ])->fetchAll();
    }

    // Получить предложения (SKU) для элемента
    public function getOffersForElement($elementId)
    {
        return CCatalogSku::getOffersList($elementId);
    }

    // Получить все предложения по списку элементов
    public function getAllOffers($elements)
    {
        $allOfferIds = [];
        foreach ($elements as $element) {
            $offers = $this->getOffersForElement($element['ID']);
            foreach ($offers as $offerGroup) {
                foreach ($offerGroup as $offer) {
                    $allOfferIds[] = $offer['ID'];
                }
            }
        }
        return $allOfferIds;
    }
}

Использование:
Код
// Использование класса в вашем основном файле
use App\IblockDataFetcher;

$fetcher = new IblockDataFetcher($arParams['IBLOCK_ID'], $arParams['CACHE_TIME']);

// Получаем ID инфоблока SKU
$skuIblockId = $fetcher->getSkuIblockId();

if ($skuIblockId) {
    // Получаем информацию об инфоблоке SKU
    $skuIblockInfo = $fetcher->getIblockInfo($skuIblockId);
}

// Получаем текущий раздел
$currentSectionId = $fetcher->getCurrentSectionId($arResult['VARIABLES']);

// Получаем элементы раздела
$listElements = $fetcher->getElementsInSection($currentSectionId);

// Получаем все предложения по элементам
$allOfferIds = $fetcher->getAllOffers($listElements);

// Передача в глобальный фильтр
$GLOBALS[$arParams["FILTER_NAME"]] = [
    'ID' => $allOfferIds,
];

Стоимость и сроки разработки сайтов и приложений

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

Интернет-магазин: индивидуальная разработка от 350 000 руб.
от 5-ти недель

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

Интернет-магазин: на готовом решении от 60 000 руб.
от 7-ми дней

Готовое решение — вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Магазин, быстро запускается на базе одного из 200-та готовых решений

Мобильное приложение от 400 000 руб.
от 1-го месяца

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Опросник на разработку. После ознакомления, задам уточняющие вопросы и оценю проект по стоимости и срокам разработки.