Разработка системы отзывов и рейтингов товаров для интернет-магазина

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

Разработка и обслуживание любых видов сайтов:

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка системы отзывов и рейтингов товаров для интернет-магазина
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы

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

Этапы разработки

Последние работы

  • 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

Разработка системы отзывов и рейтингов товаров для интернет-магазина

Отзывы — социальное доказательство, которое влияет на конверсию сильнее, чем описание товара. Средний рейтинг и количество отзывов отображаются в сниппетах Google через structured data, что даёт преимущество в поиске. Разработка системы отзывов занимает 4–7 рабочих дней.

Модель данных

CREATE TABLE reviews (
    id BIGSERIAL PRIMARY KEY,
    product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
    order_item_id BIGINT REFERENCES order_items(id), -- подтверждённая покупка
    user_id BIGINT REFERENCES users(id),
    guest_name VARCHAR(100),
    rating SMALLINT NOT NULL CHECK (rating BETWEEN 1 AND 5),
    title VARCHAR(255),
    body TEXT,
    pros TEXT,   -- Достоинства
    cons TEXT,   -- Недостатки
    status VARCHAR(20) DEFAULT 'pending', -- pending, approved, rejected, spam
    is_verified_purchase BOOLEAN DEFAULT FALSE,
    helpful_count INT DEFAULT 0,
    not_helpful_count INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE review_photos (
    id BIGSERIAL PRIMARY KEY,
    review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE,
    url VARCHAR(500) NOT NULL,
    sort_order SMALLINT DEFAULT 0
);

CREATE TABLE review_votes (
    review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE,
    user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
    vote BOOLEAN NOT NULL, -- true = helpful, false = not helpful
    PRIMARY KEY (review_id, user_id)
);

Кто может оставить отзыв

Три модели доступа:

Модель Плюсы Минусы
Только покупатели Высокое доверие Мало отзывов
Авторизованные пользователи Баланс Возможны накрутки
Все (включая гостей) Максимум отзывов Требует ручной модерации

Рекомендуется: авторизованные пользователи + пометка «Подтверждённая покупка» для тех, у кого есть завершённый заказ с этим товаром.

public function store(Request $request, Product $product): JsonResponse
{
    $request->validate([
        'rating' => 'required|integer|between:1,5',
        'body'   => 'required|string|min:20|max:2000',
        'title'  => 'nullable|string|max:255',
        'pros'   => 'nullable|string|max:500',
        'cons'   => 'nullable|string|max:500',
        'photos' => 'nullable|array|max:5',
        'photos.*' => 'url',
    ]);

    $isVerified = OrderItem::whereHas('order', fn($q) =>
        $q->where('user_id', $request->user()->id)->where('status', 'completed')
    )->where('product_id', $product->id)->exists();

    $review = Review::create([
        ...$request->validated(),
        'product_id'            => $product->id,
        'user_id'               => $request->user()->id,
        'is_verified_purchase'  => $isVerified,
        'status'                => $this->needsModeration($request) ? 'pending' : 'approved',
    ]);

    $product->recalculateRating();
    return response()->json(new ReviewResource($review), 201);
}

Модерация

Модерация может быть ручной или автоматизированной. Автоматические правила:

  • Отзыв от верифицированного покупателя с рейтингом 4–5 и без стоп-слов → approved автоматически
  • Первый отзыв нового пользователя → pending для проверки
  • Текст содержит URL, телефон или слова из стоп-листа → pending или spam
class ReviewModerationService
{
    private array $stopWords = ['http', 'www.', 't.me/', 'whatsapp'];

    public function needsModeration(string $text, User $user): bool
    {
        foreach ($this->stopWords as $word) {
            if (str_contains(strtolower($text), $word)) return true;
        }
        return $user->reviews()->where('status', 'approved')->count() === 0;
    }
}

В admin-панели — очередь отзывов на модерацию с быстрыми действиями: одобрить / отклонить / пометить спамом.

Пересчёт рейтинга товара

public function recalculateRating(): void
{
    $stats = $this->reviews()
        ->where('status', 'approved')
        ->selectRaw('COUNT(*) as count, AVG(rating) as avg, SUM(CASE WHEN rating = 5 THEN 1 ELSE 0 END) as five_star')
        ->first();

    $this->update([
        'rating_avg'   => round($stats->avg, 2),
        'rating_count' => $stats->count,
    ]);

    // Инвалидируем кеш страницы товара
    Cache::forget("product:{$this->id}:rating");
}

Рейтинг хранится денормализованно в таблице products для быстрой сортировки в каталоге.

Распределение оценок

На странице товара показывается не только средний рейтинг, но и гистограмма:

const RatingDistribution = ({ distribution }: { distribution: Record<number, number> }) => {
  const total = Object.values(distribution).reduce((a, b) => a + b, 0);

  return (
    <div className="space-y-1">
      {[5, 4, 3, 2, 1].map(star => (
        <div key={star} className="flex items-center gap-2">
          <span className="w-4 text-sm">{star}</span>
          <div className="flex-1 h-2 bg-gray-100 rounded-full overflow-hidden">
            <div
              className="h-full bg-yellow-400 rounded-full"
              style={{ width: `${((distribution[star] ?? 0) / total) * 100}%` }}
            />
          </div>
          <span className="text-sm text-gray-500 w-8">{distribution[star] ?? 0}</span>
        </div>
      ))}
    </div>
  );
};

Ответы магазина

Менеджер может отвечать на отзывы прямо из admin-панели. Ответ отображается под отзывом с пометкой «Ответ магазина»:

CREATE TABLE review_replies (
    id BIGSERIAL PRIMARY KEY,
    review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE,
    user_id BIGINT REFERENCES users(id),
    body TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

Structured data для SEO

Отзывы должны экспортироваться в JSON-LD для Google:

const ProductSchema = ({ product }: { product: ProductDetail }) => (
  <script type="application/ld+json">{JSON.stringify({
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.name,
    aggregateRating: {
      '@type': 'AggregateRating',
      ratingValue: product.rating_avg,
      reviewCount: product.rating_count,
      bestRating: 5,
      worstRating: 1,
    },
    review: product.topReviews.map(r => ({
      '@type': 'Review',
      author: { '@type': 'Person', name: r.user_name },
      reviewRating: { '@type': 'Rating', ratingValue: r.rating },
      reviewBody: r.body,
      datePublished: r.created_at,
    })),
  })}</script>
);

Звёзды в сниппете появляются в поиске при наличии минимум 1 отзыва.

Сортировка и фильтрация отзывов

На странице товара отзывы сортируются: по дате, по рейтингу (высокий/низкий), по полезности. Фильтр по количеству звёзд — кликабельные строки в гистограмме. Это помогает покупателю найти релевантные отзывы и снижает bounce rate на странице товара.