Розробка мегаменю з банерами та акціями 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С-Бітрікс

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

Управління банерами мегаменю

Банери прив'язуються до розділів каталогу через HL-блок MegaMenuBanner:

b_uts_megamenu_banner
├── UF_SECTION_ID      — розділ каталогу (b_iblock_section.ID)
├── UF_IMAGE           — зображення банера (b_file.ID)
├── UF_TITLE           — заголовок (опціонально)
├── UF_SUBTITLE        — підзаголовок
├── UF_LINK            — URL кліку
├── UF_ACTIVE_FROM     — початок показу
├── UF_ACTIVE_TO       — кінець показу
├── UF_SORT            — порядок сортування
└── UF_ACTIVE          — активність

Менеджер може змінювати банери з адміністративної частини HL-блока без залучення розробника.

Завантаження банерів при побудові меню

namespace Local\Menu;

use Bitrix\Highloadblock\HighloadBlockTable;
use Bitrix\Main\Type\DateTime;

class MegaMenuBannerRepository
{
    public static function getForSections(array $sectionIds): array
    {
        if (empty($sectionIds)) return [];

        $hlBlock = HighloadBlockTable::getById(MEGAMENU_BANNER_HLBLOCK_ID)->fetch();
        $entity  = HighloadBlockTable::compileEntity($hlBlock);
        $dataClass = $entity->getDataClass();

        $now = new DateTime();

        $res = $dataClass::getList([
            'filter' => [
                'UF_SECTION_ID' => $sectionIds,
                'UF_ACTIVE'     => true,
                [
                    'LOGIC' => 'OR',
                    ['<=UF_ACTIVE_FROM' => $now, '>=UF_ACTIVE_TO' => $now],
                    ['UF_ACTIVE_FROM'   => false],
                ],
            ],
            'order'  => ['UF_SECTION_ID' => 'ASC', 'UF_SORT' => 'ASC'],
            'select' => ['UF_SECTION_ID', 'UF_IMAGE', 'UF_TITLE', 'UF_SUBTITLE', 'UF_LINK'],
        ]);

        $result = [];
        while ($row = $res->fetch()) {
            $sectionId = $row['UF_SECTION_ID'];
            if (!isset($result[$sectionId])) {
                $result[$sectionId] = [];
            }
            $row['UF_IMAGE_SRC'] = \CFile::ResizeImageGet(
                $row['UF_IMAGE'],
                ['width' => 280, 'height' => 180],
                BX_RESIZE_IMAGE_EXACT
            )['src'] ?? null;
            $result[$sectionId][] = $row;
        }

        return $result;
    }
}

Актуальні акції в мегаменю

Паралельно з банерами — список товарів розділу, які беруть участь в акціях. Акційні товари визначаються через b_catalog_price:

public static function getDiscountedProducts(int $sectionId, int $limit = 4): array
{
    $conn = \Bitrix\Main\Application::getConnection();

    $result = $conn->query("
        SELECT
            be.ID,
            be.NAME,
            be.DETAIL_PAGE_URL,
            be.PREVIEW_PICTURE,
            base_p.PRICE   AS price,
            sale_p.PRICE   AS sale_price
        FROM b_iblock_element be
        JOIN b_iblock_section_element bse ON bse.IBLOCK_ELEMENT_ID = be.ID
        JOIN b_catalog_price base_p
            ON base_p.PRODUCT_ID       = be.ID
            AND base_p.CATALOG_GROUP_ID = 1
        JOIN b_catalog_price sale_p
            ON sale_p.PRODUCT_ID       = be.ID
            AND sale_p.CATALOG_GROUP_ID = 2  -- група «Акційна ціна»
        WHERE bse.IBLOCK_SECTION_ID = {$sectionId}
          AND be.IBLOCK_ID           = " . CATALOG_IBLOCK_ID . "
          AND be.ACTIVE              = 'Y'
          AND sale_p.PRICE           < base_p.PRICE
        ORDER BY (base_p.PRICE - sale_p.PRICE) / base_p.PRICE DESC
        LIMIT {$limit}
    ");

    $products = [];
    while ($row = $result->fetch()) {
        $row['DISCOUNT_PCT'] = round(
            ($row['price'] - $row['sale_price']) / $row['price'] * 100
        );
        $row['IMAGE_SRC'] = $row['PREVIEW_PICTURE']
            ? \CFile::ResizeImageGet($row['PREVIEW_PICTURE'], ['width' => 100, 'height' => 100], BX_RESIZE_IMAGE_PROPORTIONAL)['src']
            : null;
        $products[] = $row;
    }

    return $products;
}

Шаблон мегаменю з банером та акціями

<div class="megamenu__dropdown">
    <div class="megamenu__inner megamenu__inner--with-promo">

        <!-- Навігація по підкатегоріях -->
        <div class="megamenu__nav">
            <?php foreach ($category['children'] as $sub): ?>
            <a href="<?= htmlspecialchars($sub['SECTION_PAGE_URL']) ?>"
               class="megamenu__subcat">
                <?= htmlspecialchars($sub['NAME']) ?>
            </a>
            <?php endforeach ?>
        </div>

        <!-- Акційні товари -->
        <?php if (!empty($discounted[$category['ID']])): ?>
        <div class="megamenu__sales">
            <div class="megamenu__section-title">Знижки в розділі</div>
            <?php foreach ($discounted[$category['ID']] as $product): ?>
            <a href="<?= htmlspecialchars($product['DETAIL_PAGE_URL']) ?>"
               class="megamenu__sale-item">
                <?php if ($product['IMAGE_SRC']): ?>
                <img src="<?= $product['IMAGE_SRC'] ?>" alt="" width="56" height="56">
                <?php endif ?>
                <div>
                    <div class="megamenu__sale-name"><?= htmlspecialchars($product['NAME']) ?></div>
                    <div class="megamenu__sale-prices">
                        <span class="old"><?= number_format($product['price'], 0, '', ' ') ?> ₽</span>
                        <span class="new"><?= number_format($product['sale_price'], 0, '', ' ') ?> ₽</span>
                        <span class="badge">-<?= $product['DISCOUNT_PCT'] ?>%</span>
                    </div>
                </div>
            </a>
            <?php endforeach ?>
        </div>
        <?php endif ?>

        <!-- Банер -->
        <?php $banners = $menuBanners[$category['ID']] ?? [] ?>
        <?php if (!empty($banners[0]) && $banners[0]['UF_IMAGE_SRC']): ?>
        <div class="megamenu__banner">
            <a href="<?= htmlspecialchars($banners[0]['UF_LINK']) ?>">
                <img src="<?= $banners[0]['UF_IMAGE_SRC'] ?>"
                     alt="<?= htmlspecialchars($banners[0]['UF_TITLE'] ?? '') ?>"
                     width="280" height="180" loading="lazy">
                <?php if ($banners[0]['UF_TITLE']): ?>
                <div class="megamenu__banner-title">
                    <?= htmlspecialchars($banners[0]['UF_TITLE']) ?>
                </div>
                <?php endif ?>
            </a>
        </div>
        <?php endif ?>

    </div>
</div>

CSS grid для триколонкового layout

.megamenu__inner--with-promo {
    display: grid;
    grid-template-columns: 220px 1fr 300px;
    min-height: 320px;
}

.megamenu__sales {
    padding: 1rem 1.5rem;
    border-right: 1px solid #eee;
}

.megamenu__sale-item {
    display: flex;
    gap: 0.75rem;
    padding: 0.625rem 0;
    border-bottom: 1px solid #f0f0f0;
    text-decoration: none;
    color: inherit;
    transition: background 0.1s;
}

.megamenu__sale-prices .old {
    text-decoration: line-through;
    color: #999;
    font-size: 0.75rem;
}

.megamenu__sale-prices .new {
    font-weight: 600;
    color: var(--color-sale);
}

.megamenu__banner {
    position: relative;
    overflow: hidden;
}

.megamenu__banner img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.megamenu__banner-title {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 1rem;
    background: linear-gradient(transparent, rgba(0,0,0,.6));
    color: #fff;
    font-weight: 600;
}

Кешування та оновлення при зміні акцій

Банери та акції кешуються на 30 хвилин (акції змінюються частіше, ніж структура розділів). Інвалідація — при збереженні HL-блока банерів:

AddEventHandler('main', 'OnAfterHLBlockElementAdd', '\Local\Menu\MegaMenuCache::clear');
AddEventHandler('main', 'OnAfterHLBlockElementUpdate', '\Local\Menu\MegaMenuCache::clear');

Терміни реалізації

Конфігурація Термін
Банери через HL-блок + виведення в мегаменю 3–4 дні
+ акційні товари з b_catalog_price +2 дні
+ ротація банерів, обмеження за датами +1–2 дні