Разработка доски объявлений на 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка доски объявлений на 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1181
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    813
  • 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 Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Разработка доски объявлений на 1С-Битрикс

Доска объявлений — сложнее, чем кажется на первый взгляд. Это не просто «список товаров». Пользователи сами размещают объявления, модераторы проверяют контент, нужны поиск с фильтрами по многим параметрам, управление статусами и сроками объявлений, платное продвижение, личный кабинет продавца. Битрикс даёт хорошую базу — инфоблоки, модуль пользователей, фасетный поиск — но конкретную логику доски нужно строить поверх.

Структура инфоблока объявлений

Инфоблок — основное хранилище. Символьный код: classifieds. Тип: ADS.

Обязательные свойства инфоблока:

Свойство Код Тип
Цена PRICE Число
Тип сделки DEAL_TYPE Список (Продам/Куплю/Обменяю/Отдам)
Город CITY Справочник (HL-блок)
Телефон продавца PHONE Строка
Статус AD_STATUS Список (Активно/Модерация/Отклонено/Истекло)
Дата истечения EXPIRE_DATE Дата
Просмотры VIEW_COUNT Число
VIP IS_VIP Флаг
Пользователь USER_ID Число (FK на b_user)
Фотографии PHOTOS Файл (множественное)

Раздел инфоблока — категория объявлений (Транспорт, Недвижимость, Электроника и т.д.). Иерархия разделов — дерево через b_iblock_section.

Размещение объявления пользователем

Форма добавления объявления — страница в /ads/add/. Ключевой момент: пользователь загружает контент, значит нужна защита от спама и обязательная модерация.

// /local/components/local/ads.add/class.php

namespace Local\Ads;

class AdsAddComponent extends \CBitrixComponent
{
    public function executeComponent(): void
    {
        if (!$GLOBALS['USER']->IsAuthorized()) {
            LocalRedirect('/auth/?backurl=/ads/add/');
            return;
        }

        if ($this->request->isPost() && check_bitrix_sessid()) {
            $this->addAd();
        }

        $this->includeComponentTemplate();
    }

    private function addAd(): void
    {
        $el = new \CIBlockElement();

        // Обработка загруженных фотографий
        $photos = [];
        if (!empty($_FILES['PHOTOS']['tmp_name'])) {
            foreach ($_FILES['PHOTOS']['tmp_name'] as $i => $tmpName) {
                if (is_uploaded_file($tmpName)) {
                    $photos[] = [
                        'name'     => $_FILES['PHOTOS']['name'][$i],
                        'size'     => $_FILES['PHOTOS']['size'][$i],
                        'tmp_name' => $tmpName,
                        'type'     => $_FILES['PHOTOS']['type'][$i],
                    ];
                }
            }
        }

        $adId = $el->Add([
            'IBLOCK_ID'      => CLASSIFIEDS_IBLOCK_ID,
            'NAME'           => htmlspecialchars($this->request->getPost('title')),
            'DETAIL_TEXT'    => htmlspecialchars($this->request->getPost('description')),
            'IBLOCK_SECTION_ID' => (int)$this->request->getPost('category_id'),
            'ACTIVE'         => 'N', // Изначально неактивно, до модерации
            'PROPERTY_VALUES' => [
                'PRICE'      => (float)$this->request->getPost('price'),
                'DEAL_TYPE'  => $this->request->getPost('deal_type'),
                'PHONE'      => htmlspecialchars($this->request->getPost('phone')),
                'USER_ID'    => $GLOBALS['USER']->GetID(),
                'AD_STATUS'  => 'MODERATION',
                'EXPIRE_DATE' => date('d.m.Y', strtotime('+30 days')),
                'VIEW_COUNT'  => 0,
                'PHOTOS'     => $photos,
            ],
        ]);

        if ($adId) {
            $this->arResult['SUCCESS'] = true;
            $this->arResult['AD_ID']   = $adId;
            // Уведомить модераторов
            $this->notifyModerators($adId);
        } else {
            $this->arResult['ERROR'] = $el->LAST_ERROR;
        }
    }
}

Модерация

Страница модератора — стандартный список элементов инфоблока с фильтром по AD_STATUS = MODERATION. Действия модератора меняют статус и активность:

// Одобрить объявление
$el = new \CIBlockElement();
$el->Update($adId, ['ACTIVE' => 'Y']);
\CIBlockElement::SetPropertyValues($adId, CLASSIFIEDS_IBLOCK_ID, 'ACTIVE', 'AD_STATUS');

// Отклонить с причиной
\CIBlockElement::SetPropertyValues($adId, CLASSIFIEDS_IBLOCK_ID, [
    'AD_STATUS'     => 'REJECTED',
    'REJECT_REASON' => $reason,
]);
$el->Update($adId, ['ACTIVE' => 'N']);

// Уведомить пользователя
$event = new \Bitrix\Main\Mail\Event([
    'EVENT_NAME' => 'AD_MODERATION_RESULT',
    'LID'        => SITE_ID,
    'C_FIELDS'   => [
        'AD_ID'  => $adId,
        'STATUS' => $status,
        'REASON' => $reason,
    ],
]);
$event->send();

Поиск и фильтрация

Фильтр объявлений — критическая часть UX. Для простого поиска — стандартный CIBlockElement::GetList() с фильтром. Для нагруженного проекта — фасетный поиск Битрикс (модуль search) или интеграция с ElasticSearch.

Пример фильтра с диапазоном цен:

$filter = [
    'IBLOCK_ID'  => CLASSIFIEDS_IBLOCK_ID,
    'ACTIVE'     => 'Y',
    'SECTION_ID' => $categoryId,
    '>PROPERTY_PRICE'  => $priceMin,
    '<PROPERTY_PRICE'  => $priceMax,
    'PROPERTY_CITY'    => $cityId,
    'PROPERTY_AD_STATUS' => 'ACTIVE',
];

$sort = ['PROPERTY_IS_VIP' => 'DESC', 'DATE_ACTIVE_FROM' => 'DESC'];

VIP-объявления всегда наверху через сортировку по флагу IS_VIP DESC.

Истечение срока объявлений

Агент проверяет просроченные объявления:

// Регистрация агента в /local/php_interface/init.php
\CAgent::AddAgent(
    'Local\\Ads\\ExpireAgent::run();',
    'local.ads',
    'N',
    86400, // Раз в сутки
);

// Метод агента
class ExpireAgent
{
    public static function run(): string
    {
        $today = date('d.m.Y');
        $result = \CIBlockElement::GetList(
            [],
            [
                'IBLOCK_ID'         => CLASSIFIEDS_IBLOCK_ID,
                'ACTIVE'            => 'Y',
                '<PROPERTY_EXPIRE_DATE' => $today,
            ],
            false,
            false,
            ['ID', 'PROPERTY_USER_ID']
        );

        while ($ad = $result->Fetch()) {
            $el = new \CIBlockElement();
            $el->Update($ad['ID'], ['ACTIVE' => 'N']);
            \CIBlockElement::SetPropertyValues($ad['ID'], CLASSIFIEDS_IBLOCK_ID, 'EXPIRED', 'AD_STATUS');
            // Уведомить пользователя
        }

        return 'Local\\Ads\\ExpireAgent::run();';
    }
}

Личный кабинет пользователя

Страница /personal/ads/ — список объявлений текущего пользователя:

$myAds = \CIBlockElement::GetList(
    ['DATE_CREATE' => 'DESC'],
    [
        'IBLOCK_ID'       => CLASSIFIEDS_IBLOCK_ID,
        'PROPERTY_USER_ID' => $GLOBALS['USER']->GetID(),
    ],
    false,
    ['nPageSize' => 20],
    ['ID', 'NAME', 'ACTIVE', 'PROPERTY_AD_STATUS', 'PROPERTY_EXPIRE_DATE', 'PROPERTY_VIEW_COUNT']
);

Действия пользователя: редактировать, деактивировать, продлить срок (если объявление истекло), удалить.

Счётчик просмотров

При каждом открытии детальной страницы — инкрементировать счётчик. Через AJAX, чтобы не замедлять начальный рендер и не считать ботов:

// /local/ajax/ad_view.php
$adId = (int)$_POST['ad_id'];
if ($adId > 0) {
    $current = (int)\CIBlockElement::GetProperty(CLASSIFIEDS_IBLOCK_ID, $adId, [], ['CODE' => 'VIEW_COUNT'])->GetNext()['VALUE'];
    \CIBlockElement::SetPropertyValues($adId, CLASSIFIEDS_IBLOCK_ID, $current + 1, 'VIEW_COUNT');
}

Сроки разработки

Вариант Состав Срок
Базовая доска Инфоблок, размещение, список, фильтр 8–12 дней
С модерацией и ЛК + Модерация, личный кабинет, агент истечения 12–18 дней
Полнофункциональная + VIP-объявления, поиск, уведомления, статистика 20–30 дней