Интернет-магазины

Колесо Трейдинг: полное обновление интернет-магазина шин

Магазин шин на 17 тысяч позиций: новый интерфейс, три способа подбора, ускорение в пять раз и переделанная структура каталога — без остановки продаж.

Ниша
Шины
Тип проекта
Полное обновление интернет-магазина шин
Платформа
OpenCart 3
Адрес
koleso-trading.com
Колесо Трейдинг — экран 1
Колесо Трейдинг — экран 2
Колесо Трейдинг — экран 3
01 Задача

Магазин работал и приносил заказы, но вырос быстрее, чем его код. Каталог на 17 тысяч шин обновлялся ночной выгрузкой поставщика, и эта выгрузка не укладывалась в отведённое время, а при сбое у поставщика могла обнулить каталог целиком. Журнал ошибок дорос до 6,4 ГБ, база — до 7,3 ГБ, из которых 7,1 ГБ занимали просроченные сессии. У карточек товаров не было ни человеческих адресов, ни canonical, и 42 % каталога пересоздавалось за месяц — проиндексированные страницы постоянно умирали. Карты сайта не было вовсе. Главная отвечала от одной до шести секунд. Отдельная беда — подбор: покупатель, который знает только марку своей машины, найти шины не мог, а поиск отделения Новой Почты не работал вообще.

02 Решение

Сначала подняли полную копию магазина с отдельной базой — всё делалось на ней, боевой сайт не останавливался ни на день. Тему решили не переписывать: в ней 13 собственных модулей, и 31 из 39 установленных патчей завязан на её шаблоны. Вместо этого завели свой слой стилей, который подключается последним, и переписали интерфейс поверх рабочего движка — карточку товара, шапку с мегаменю, фильтр, оформление заказа, тёмную тему и всю адаптацию под телефон. Параллельно переделали то, что не видно: структуру каталога, постоянные адреса товаров, ночной обмен, кеширование и индексы. Переключение на новую версию заняло 11 минут простоя.

03 Результат

Главная отвечает за 0,2 секунды вместо шести, ночное обновление каталога проходит за 74 секунды одним проходом, адрес карточки больше не меняется никогда, а карта сайта на 35 тысяч адресов пересобирается каждую ночь. Покупатель подбирает шины тремя способами — по типоразмеру, по автомобилю и разноширокими комплектами, — видит цены всех складов в одной карточке и получает рабочую доставку Новой Почтой. Заявки дублируются в Telegram, формы закрыты от ботов.

Что сделали

Состав работ по проекту

Интерфейс переписан поверх темы

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

Три способа подбора шин

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

Цены всех складов в карточке

Предложения по городам сортируются по цене, лучшее отмечено; год выпуска, остаток и страна — у каждого склада свои.

Структура каталога и адреса

Корень «Шины», четыре типа транспорта, 15 сезонных посадочных страниц и постоянный адрес у каждой карточки вместо ссылки с номером товара.

Ускорение в пять раз

Индексы, кеш списков и движка, прогрев после ночного обмена, отложенная загрузка картинок и свои шрифты без обращений к Google.

Ночной обмен переписан

74 секунды вместо четырёх заданий подряд, защита от пустого прайса и отказ от удаления товаров — вернувшаяся позиция получает прежний адрес.

5,7 → 0,2 с
ответ главной страницы
74 с
полное обновление каталога
11 мин
простой при переключении
~35 000
адресов в карте сайта

Что внутри

  • OpenCart 3
  • PHP
  • MySQL
  • собственный слой стилей
  • ocmod
  • SEO-структура
Исходное состояние

С чего начинали

Первым делом разобрали журналы и базу — до единой правки в коде. Файл ошибок занимал 6,4 ГБ, и 99,98 % его содержимого оказалось одной повторяющейся ошибкой в генераторе товарного фида: около 1,1 миллиона одинаковых записей. За ней в логе пряталось всё остальное — в том числе ошибки подборщика шин и Новой Почты, которые как раз ломали покупателю сценарий заказа.

В базе 7,1 ГБ из 7,3 занимала таблица сессий с 26,8 миллионами просроченных строк. Причина оказалась в одной строке драйвера: срок жизни сессии сравнивался с датой как с числом, поэтому уборщик не удалял ничего и никогда. По той же причине сессии не истекали вовсе.

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

Что смотрелиБылоСтало
Ответ главной страницы1–5,7 секунды0,2 секунды
Витрина каталога4,5 секунды1,0 секунды
Страница фильтра3,7–5,4 секунды0,4–1,3 секунды
Ночное обновление каталогане укладывалось в четыре задания подряд74 секунды одним проходом
Журнал ошибок6,4 ГБ, 1,1 млн одинаковых записейпустой
Таблица сессий7,1 ГБ, 26,8 млн просроченных строкчистится ночью, окно 20 дней
Адрес карточки товара/shiny?product_id=1530939, без canonical/continental-wintercontact-ts-870p-225-55-r17-97h
Карта сайтаотсутствовалаоколо 35 000 адресов, собирается каждую ночь
Страницы брендов614 пустых отдавали 200, а 68 рабочих — 404пустые скрываются сами, рабочие открыты
Разделы каталогавсе шины в одном разделе, мотошины выключенычетыре типа транспорта и 15 сезонных страниц
Отделения Новой Почтыпоиск города не работал вообщеработает
Главная до обновления
Главная до обновления
Главная после обновления
Главная после обновления
Дизайн и интерфейс

Новый вид поверх работающего магазина

Переписывать тему с нуля мы не стали, и это было осознанное решение, а не экономия. В теме 13 собственных модулей, а 31 из 39 установленных в магазине патчей правит именно её шаблоны: замена темы означала бы переделку всего магазина разом и остановку продаж на недели.

Вместо этого завели собственный слой стилей, который подключается последним и ничего в теме не затирает. Там, где правки касались шаблонов, они вносились и в оригинал, и в собранную движком копию — иначе первое же нажатие «обновить модификации» в админке стёрло бы всё без единой ошибки в журнале.

Карточка товара

Собрана заново: название в две строки — бренд с моделью и отдельно типоразмер, логотип бренда, метка наличия, характеристики плашками под фотографией, блоки с описанием, европейской этикеткой, похожими моделями и отзывами.

Склады и цены по городам

Вместо таблицы — плашки: город, год выпуска, остаток и страна с флагом у каждого предложения. Они отсортированы по цене, лучшее отмечено, а выбор склада подставляется в форму заказа, чтобы покупка не ушла не с того города.

Шапка и мегаменю

Поиск с подсказками, два номера со значками операторов, переключатель языка и ночного режима, плашки ходовых диаметров. В мегаменю — типы транспорта, сезоны, бренды и типоразмеры одним экраном.

Боковой фильтр

Списки размеров с поиском внутри, разделением на ходовые и остальные и честными счётчиками. Отдельная галочка включает режим разношироких шин с двумя осями.

Тёмная тема

Доведена по всему сайту, а не только на главной: ссылки и кнопки, подложки, фотографии товаров, текстовые страницы, фильтр, всплывающие окна и оформление заказа. Расхождения искали обходом страниц, а не на глаз.

Адаптив

Ниже 1200 пикселей фильтр уходит в выдвижную панель, а витрина занимает ширину экрана; ниже 992 шапка перестраивается в две строки. На устройствах без мыши мегаменю открывается нажатием — раньше оно мелькало и сразу уходило на страницу каталога.

Оформление заказа

Одностраничное оформление приведено к стилю сайта: формы слева, корзина справа и едет за прокруткой, поля и кнопки в общей геометрии, своя ночная тема. На телефоне корзина идёт первой.

Единая система подсказок

Один механизм на весь сайт: достаточно пометить элемент — и подсказка появится у курсора. Написан без лишних зависимостей и работает на динамически добавленных блоках.

Карточка товара: предложения всех складов с ценами, годом выпуска и остатком
Карточка товара: предложения всех складов с ценами, годом выпуска и остатком
Та же витрина в ночном режиме
Та же витрина в ночном режиме
Функционал

Как покупатель находит свой размер

Шины ищут тремя разными способами, и каждый требует своего механизма. Кто-то переписывает размер с боковины, кто-то знает только марку и год машины, а у части автомобилей спереди и сзади стоят разные шины — такой комплект обычный фильтр каталога собрать не может в принципе, потому что условие «у модели есть обе оси в наличии» относится к модели, а не к товару.

Поэтому подбор сделан тремя входами, и все три доступны с главной, из шапки и из фильтра.

Подбор по типоразмеру

Ширина, высота, диаметр плюс бренд, сезон и шипы. Списки связаны между собой: выбранная ширина оставляет только те высоты и диаметры, которые с ней действительно бывают.

Подбор по автомобилю

Марка, модель, год и двигатель. Результат разложен на заводскую комплектацию и варианты замены, а если у машины разноширокий комплект — он показан одной плашкой с передней и задней осью, а не плоским списком, в котором не разобрать, где перед, а где зад.

Разноширокие комплекты

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

Европейская этикетка

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

Модели шин как отдельная сущность

1220 моделей со своими страницами, адресами и текстами. Тексты хранятся отдельно от товаров, поэтому ночная выгрузка их не затирает — это и было главным требованием владельца.

Популярные типоразмеры

Отдельная страница и блок на главной: в каждом размере — сезоны, что есть в наличии, и бренды этого размера.

Уведомления в Telegram

Новый заказ, обратный звонок, заявка «нашли дешевле», сообщение с формы, отзыв, подписка и регистрация. В заказе — состав со ссылками на товары, доставка, оплата и телефон в том виде, который Telegram сам делает кликабельным.

Защита форм от ботов

После того как в заявки полетел спам, поставили четыре независимых заслона: невидимое поле-ловушку, метку открытия формы, ограничение частоты и маску номера. Все отвечают одинаковой ошибкой, чтобы по ответу нельзя было понять, какой сработал.

Доставка и оплата

Починен поиск города и выбор отделения Новой Почты — он не работал вообще, покупатель всегда видел «не найдено». Наличные и терминал доступны только при самовывозе, способы оплаты упорядочены.

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

Где магазин терял секунды

Владелец пожаловался на задержку в три-четыре секунды при переходе на главную. Замер показал разброс от одной до 5,7 секунды, и причина нашлась быстро: шесть запросов, которые наполняют списки в блоке подбора, выполнялись заново на каждой странице, где этот блок есть, и вместе занимали 4,26 секунды. Они перебирали таблицу атрибутов на 1,17 миллиона строк.

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

Отдельная находка: кеш самого движка писался, но не читался — в библиотеке кеша стояло условие, по которому записи отдавались только для справочника городов. Чтение вернули, а сброс повесили на конец ночного обмена. Это и дало основной выигрыш по всем страницам сразу.

  • Ночной обмен переписан: полный прогон за 74 секунды вместо четырёх заданий подряд, память 59 МБ вместо сотен, поиск товаров внутри прогона — 3 секунды вместо 85.
  • Два составных индекса на таблицу товаров: план запроса изменился с перебора 17 тысяч строк на выборку одной.
  • Справочник атрибутов перечитывался запросом на каждый атрибут каждого товара — около 190 тысяч лишних запросов за прогон. Заменён кешем в памяти.
  • Отложенная загрузка картинок проставлена в шаблонах — 57 тегов; на главной откладывается 34 изображения из 101, и больше всего выигрывает меню с логотипами брендов.
  • Шрифт перенесён к себе: 10 файлов по языковым подмножествам вместо запроса к шрифтам Google, которого ждала каждая страница.
  • Ночная чистка сессий порциями по 50 тысяч строк, с собственным индексом и ограничением по времени — таблица больше не растёт.
СтраницаБылоСтало
Главная1,2 с0,2 с
Витрина каталога4,5 с1,0 с
Страница фильтра3,7–5,4 с0,4–1,3 с
Карточка товара0,9–3,9 с0,37 с
Первая отрисовка в браузере6,3 с1,8 с
Полная загрузка главной8,4 с3,5 с
SEO и техническая часть

Структура, адреса и индексация

Главной SEO-проблемой были не тексты, а адреса. Карточка открывалась как /shiny?product_id=1530939, причём префикс зависел от того, откуда пришёл посетитель, canonical не было вовсе, а ночной обмен удалял выбывшие товары и заводил вернувшиеся заново — с новым номером. За восемь месяцев было израсходовано около 623 тысяч номеров при 17 тысячах товаров в каталоге; 42 % каталога пересоздавалось в течение месяца. Проиндексированные страницы просто отмирали.

Три изменения пришлось делать одной связкой, по отдельности они не работают: обмен перестал удалять товары, адрес стал собираться из того, что не меняется, и выданный адрес больше не пересчитывается.

Постоянный адрес у карточки

Собирается из замороженного слага модели и типоразмера, а не из названия, которое поставщик правит (274 правки за восемь прогонов). Выдаётся один раз и хранится в собственном реестре. Старые адреса с номером товара отдают 301 на короткий.

Товары больше не удаляются

Выбывшая позиция остаётся с нулевым остатком и пропадает из списков и фильтров; вернулась в прайс — вернулась с тем же адресом. Не появлялась год — выводится из каталога и отдаёт 410 Gone: для поисковика это «страницы больше не будет».

Структура каталога

Корень «Шины», под ним четыре типа транспорта, а сезоны — отдельные посадочные страницы со своими заголовками и метатегами, 15 штук. Схема обошлась без правки стороннего модуля фильтра, поэтому переживёт его обновление.

Белый список индексации

Индексируются корень, четыре раздела и сезонные страницы; любые другие комбинации фильтров работают для покупателя, но в индекс не идут. Заодно исправлен запрет обхода ссылок, из-за которого робот не доходил до товаров.

Бренды приведены в порядок

Из 731 бренда товары были у 117: 614 пустых страниц отдавали код 200 с пустым содержимым. Пустые теперь скрываются автоматически, а 68 брендов с товарами, которые годами отдавали 404 из-за отсутствующей записи в базе, снова открываются.

Своя карта сайта

Штатный модуль был выключен, а сервер всё равно перенаправлял на него — отсюда пустой ответ. Написан свой генератор: около 35 тысяч адресов в нескольких файлах, сборка в конце ночного обмена.

robots.txt под новую структуру

Каталог, бренды и информационные страницы открыты; служебные маршруты, корзина, оформление, сортировки и постраничная навигация закрыты, как и все 28 параметров фильтра.

Редиректы и фид

Все адреса прежнего сайта прогнаны запросами: ни один не уходит в 404. В товарном фиде для Google треть позиций не выгружалась — причину нашли и устранили.

Процесс

Как шла работа

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

Разбор

Журналы, база, код ночного обмена, структура каталога и то, что доступно из интернета. До первой правки стало понятно, что чинить в первую очередь, а что только кажется проблемой.

Копия магазина

Полная копия с отдельной базой, закрытая паролем и запретом индексации, с отключённой аналитикой и переписанными ссылками на боевой домен. Все работы шли на ней.

Итерации по спискам замечаний

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

Переключение

Заглушка с кодом 503 и заголовком «вернёмся через десять минут», финальная синхронизация заказов уже под заглушкой — она подобрала два заказа, пришедших за семнадцать минут до переключения, — обмен папок, настройка и проверка. Простой составил 11 минут.

Доводка после запуска

Возвращена аналитика, переписан robots.txt, проверены все редиректы, собрана карта сайта, настроена ночная чистка сессий и прогрев кеша. Старая версия сохранена отдельно и закрыта от поисковиков.

Вопросы

Что обычно спрашивают об этом проекте

Потому что в теме магазина 13 собственных модулей, а 31 из 39 установленных патчей правит именно её шаблоны. Замена темы означала бы переписать магазин целиком и остановить продажи на недели. Собственный слой стилей и точечные правки дали тот же результат по внешнему виду, но без простоя.

Нет. Всё делалось на полной копии с отдельной базой, боевой сайт продолжал принимать заказы. Остановка была одна — 11 минут в момент переключения, под заглушкой с кодом 503, которая объясняет поисковику, что это временно.

Ничего. Адрес собирается из слага модели и типоразмера, выдаётся один раз и больше не пересчитывается, а выбывшие товары не удаляются — они просто перестают показываться. Вернулась позиция в прайс — открывается по прежнему адресу.

Потому что пока в них нет текстов. Сущность, адреса, страницы и раздел админки готовы, 1220 моделей заведены. Владелец наполняет их описаниями — после этого страницы открываются для индекса и попадают в карту сайта следующей же ночью.

Около трёх недель плотной работы — от разбора логов до переключения на новую версию, плюс доводка после запуска. Большая часть времени ушла не на вёрстку, а на структуру каталога, адреса товаров и ночной обмен.

Да, подход не зависит от CMS: разбор узких мест, копия для работ, свой слой поверх существующего кода и переключение с минимальным простоем. Мы так же работаем с WordPress, WooCommerce и самописными каталогами.

Нужен похожий проект?

Разберём вашу задачу, покажем варианты решения и назовём сроки со сметой. Бесплатно и без обязательств.