Разработка списка избранного (Wishlist) для интернет-магазина

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка списка избранного (Wishlist) для интернет-магазина
Простая
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка списка избранного (Wishlist) для интернет-магазина

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

Сценарии использования

Три основных сценария, каждый с разными техническими требованиями:

«Куплю потом» — быстрое сохранение для возврата. Не требует авторизации, достаточно localStorage.

«Слежу за ценой» — пользователь хочет уведомление при снижении цены. Требует email/push + авторизованный аккаунт.

«Подарочный список» (Gift Registry) — публичный или ссылочный список, которым делятся с другими. Требует серверное хранение + уникальный URL.

Хранение и синхронизация

Анонимный пользователь: список в localStorage. При загрузке страницы — инициализация store из localStorage.

Авторизованный пользователь: список в БД, localStorage как кеш. При авторизации — merge:

async function mergeWishlists(localItems: number[], userId: number) {
  const serverItems = await api.getWishlist(userId);
  const merged = [...new Set([...serverItems, ...localItems])];
  await api.syncWishlist(userId, merged);
  localStorage.removeItem('wishlist'); // очищаем local после merge
  return merged;
}

Схема БД:

wishlists (
  id, user_id, name, slug,
  is_public BOOLEAN DEFAULT FALSE,
  share_token VARCHAR(32),  -- для ссылочного доступа
  created_at
)

wishlist_items (
  id, wishlist_id, product_id, variant_id,
  note TEXT,               -- личная заметка к товару
  added_at TIMESTAMPTZ,
  price_at_addition NUMERIC  -- цена в момент добавления
)

Один пользователь может иметь несколько вишлистов (основной + «для спальни» + «подарочный»). Для большинства магазинов достаточно одного списка на пользователя — усложнять не стоит без явной потребности.

Кнопка «В избранное»

Иконка сердца (или закладки) на карточке товара в листинге и на странице товара. Два состояния: пустая / заполненная, с анимацией перехода.

function WishlistButton({ productId }: { productId: number }) {
  const { isInWishlist, toggle, isLoading } = useWishlist(productId);

  return (
    <button
      onClick={() => toggle(productId)}
      disabled={isLoading}
      aria-label={isInWishlist ? 'Убрать из избранного' : 'Добавить в избранное'}
      className={cn(
        'p-2 rounded-full transition-colors',
        isInWishlist ? 'text-red-500' : 'text-gray-400 hover:text-red-400'
      )}
    >
      <HeartIcon filled={isInWishlist} className="w-5 h-5" />
    </button>
  );
}

function useWishlist(productId: number) {
  const store = useWishlistStore();
  const [isLoading, setIsLoading] = useState(false);

  const toggle = async (id: number) => {
    setIsLoading(true);
    try {
      if (store.has(id)) {
        store.remove(id);
        if (isAuthenticated) await api.removeFromWishlist(id);
      } else {
        store.add(id);
        if (isAuthenticated) await api.addToWishlist(id);
      }
    } finally {
      setIsLoading(false);
    }
  };

  return { isInWishlist: store.has(productId), toggle, isLoading };
}

Оптимистичный UI: обновляем состояние в store сразу (без ожидания API). Если запрос к серверу упал — откатываем через try/catch. Пользователь видит мгновенную реакцию.

Страница вишлиста

Список избранного — отдельная страница в личном кабинете (/account/wishlist) или публичная страница при шаринге (/wishlist/{slug}).

Интерфейс страницы:

  • Грид товаров — те же карточки, что в каталоге, с кнопкой «Убрать»
  • Фильтр: по наличию, по дате добавления, по снижению цены
  • Сортировка: по дате добавления, по цене (возрастание/убывание), по изменению цены
  • «Добавить всё в корзину» — batch-операция, добавляет доступные товары
  • Статус наличия: «Нет в наличии» — визуально отмечается, но остаётся в списке

Для каждого товара показываем price_at_addition vs текущая цена — сразу видно, выросла или снизилась цена с момента добавления. Снижение цены — со значком «▼ −12%».

Уведомления о снижении цены

Пользователь может подписаться на уведомление об изменении цены товара в вишлисте:

price_alerts (
  id, user_id, product_id,
  threshold_type,        -- 'any_drop' | 'percent_drop' | 'target_price'
  threshold_value,       -- для percent_drop: 10 (10%), для target_price: 2990
  is_active BOOLEAN,
  last_notified_at
)

Процесс отправки уведомлений (запускается через scheduler раз в час или при обновлении цены):

// Laravel Job: CheckPriceAlerts
foreach ($alerts as $alert) {
    $currentPrice = $alert->product->price;
    $shouldNotify = match ($alert->threshold_type) {
        'any_drop'      => $currentPrice < $alert->product->previous_price,
        'percent_drop'  => ($currentPrice / $alert->product->previous_price - 1) <= -$alert->threshold_value / 100,
        'target_price'  => $currentPrice <= $alert->threshold_value,
    };

    if ($shouldNotify && $alert->last_notified_at < now()->subDays(3)) {
        Mail::to($alert->user)->queue(new PriceDropNotification($alert->product, $currentPrice));
        $alert->update(['last_notified_at' => now()]);
    }
}

Ограничение частоты уведомлений (last_notified_at < now()->subDays(3)) — чтобы не спамить при волатильных ценах.

Шаринг вишлиста

При включении «Поделиться списком» — генерируется share_token:

$wishlist->update([
    'is_public' => true,
    'share_token' => Str::random(32),
]);
return "/wishlist/{$wishlist->share_token}";

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

Кнопка «Скопировать ссылку» + кнопки «Поделиться в Telegram / WhatsApp» с предзаполненным текстом.

Интеграция с email-маркетингом

Wishlist — ценный сегмент для персонализированных рассылок:

  • «В вашем избранном распродажа» — при старте акции проверяем пересечение товаров в вишлистах с распродажными товарами
  • «Товар из вашего избранного заканчивается» — остаток < 3 шт.
  • «Вы давно не заходили — вот что изменилось в вашем списке» — реактивационное письмо

Реализация: при событии (старт акции / изменение остатка) — асинхронная задача в очереди, которая собирает пользователей с этим товаром в вишлисте и отправляет персонализированные письма через ESP (Mailchimp, Sendpulse).

Счётчик на иконке вишлиста

В навигации — иконка сердца с бейджем (количество товаров в списке). Бейдж обновляется мгновенно через store, не через API-запрос при каждом рендере.

function WishlistNavIcon() {
  const count = useWishlistStore(state => state.items.length);
  return (
    <div className="relative">
      <HeartIcon className="w-6 h-6" />
      {count > 0 && (
        <span className="absolute -top-1 -right-1 bg-red-500 text-white
                         text-xs rounded-full w-4 h-4 flex items-center justify-center">
          {count > 99 ? '99+' : count}
        </span>
      )}
    </div>
  );
}

SEO-аспекты

Личные вишлисты (/account/wishlist) — закрыты авторизацией, не индексируются. Публичные shared-вишлисты — noindex по умолчанию, если не реализована редакционная концепция «коллекций» с уникальным контентом.

Аналитика

  • Какие товары чаще добавляют в избранное — сигнал популярности, альтернатива sales_count для новинок
  • Wishlist-to-purchase conversion rate: % пользователей, купивших товар из вишлиста
  • Среднее время от добавления в вишлист до покупки — помогает настроить тайминг email-триггеров

Сроки

  • Базовый wishlist (localStorage, кнопка на карточке, страница списка без авторизации): 2–4 рабочих дня
  • С серверным хранением, merge при авторизации, уведомлениями о цене: 1.5–2.5 недели
  • Шаринг вишлиста, несколько списков, интеграция с email-маркетингом: 2.5–4 недели