Smartway — переезд сайта сервиса командировок на WordPress
B2B-сервис управления командировками (travel-tech SaaS) · Travel-tech / корпоративные командировки (business travel management, B2B SaaS)
Маркетинговый сайт из девяти лендингов жил на конструкторе — теперь тексты и картинки правит контент-менеджер, а страница вдвое легче лимита ТЗ.
- PHP
- JavaScript
- HTML
- CSS/SCSS
- WordPress
- классическая тема (Underscores _s)
- SCF (Secure Custom Fields)
- ACF Flexible Content
- Gutenberg (ACF-блоки)
- Contact Form 7
- Flamingo
- FluentSMTP
- Yoast SEO (JSON-LD)
- Redirection
- IndexNow
- WP Super Cache
- MySQL
- Splide
- GLightbox
- intl-tel-input
- WebP/AVIF
- Apache/Nginx
- shared hosting (reg.ru)
- WP-CLI
- rsync
- Git
- Playwright
- REST API
- Composer/WPCS
В цифрах
- 41 → 14
- активных плагинов после чистки (Фаза 2)
- 11 → 3
- mu-plugins (удалён agent-bridge → закрыта дыра REST sw-agent/v1)
- 22
- страницы статичной вёрстки dist перенесены в тему
- 58
- ACF Flexible Content layout-ов в библиотеке (9 лендингов + главная + auth/legal, весь контент в админку)
- 366
- ассетов фронта импортировано в медиатеку (SVG через safe-svg)
- 457
- изображений сконвертировано в WebP (cwebp -q80, used-only)
- 19
- записей client → case мигрировано + 301-редиректы /clients/* → /cases/* (D1)
- 10 → 6
- дедупликация экспертов (CNT-03) с сохранением реального контента + 301 surname → full-name
- ≥2,3×
- запас по KPI ТЗ: вес ≤526 КБ, JS ≤79 КБ, CSS ≤58 КБ gzip, CLS=0 (лимиты ТЗ: 1,2 МБ / 300 / 200 КБ)
- 37 → 19 мс
- серверный TTFB кэш-хита после WPSC mod_rewrite + preload (6E)
- 2,23 ГБ + 127 МБ
- ai1wm-бэкапы и осиротевший GeoIP вынесены из вебрута; uploads 332 → 206 МБ; −260 ревизий (6B)
- 10 находок (0×P0, 1×P1, 3×P2, 4×P3, 2×info)
- QA-аудит Фазы 7 против dist (43 скриншота)
- 31 раздел / 40 скриншотов
- HTML-руководство администратора (самодостаточное, офлайн)
- 11 правок / 7 кластеров
- новая волна доработок заказчика — завершена и верифицирована
Ключевое
- Пришёл новым подрядчиком после другой команды: начал с полного аудита, дальше вёл проект от вёрстки до сервера.
- Собрал конструктор из 58 блоков, из которых редактор складывает страницы — без единой строчки кода.
- Плагинов на сайте стало 14 вместо 41; из открытой части вынесено 2,23 ГБ архивов, закрыт служебный вход, через который сайтом можно было управлять снаружи.
- Сделал поисковый фундамент переезда: адреса страниц, перенаправления со старых адресов, разметка для поисковиков, хлебные крошки и оглавления статей.
- Написал руководство администратора на 31 раздел с 40 скриншотами — заказчик работает с сайтом сам.
Задача
Smartway — российский сервис, через который компании организуют командировки сотрудников: билеты, отели, такси, согласование поездок и отчётность. Маркетинговый сайт жил на конструкторе, и это упиралось в потолок: закрытый код нечем оптимизировать под поиск, а вес страниц и адреса разделов не в руках владельца.
Переезд начинала другая команда и остановилась на полпути. Тексты лендингов оказались вшиты в код — поменять слово на странице мог только разработчик. Аудит вдобавок показал, что полные архивы сайта скачивались с него любым желающим, а через служебный интерфейс сайтом можно было управлять снаружи.
Что сделано
- Пришёл новым подрядчиком после другой команды и начал с полного разбора: что уже сделано, что сломано, что опасно. По итогам согласовал с заказчиком стратегию «адаптировать, не пересобирать» — чужой работающий код был сохранён, а не переписан заново.
- Перенёс 22 страницы вёрстки на новый сайт один в один с исходным макетом и собрал конструктор из 58 блоков: теперь тексты, картинки и кнопки девяти лендингов и главной складываются в админке.
- Навёл порядок в хозяйстве сайта: убрал лишние плагины, заменил нелицензионную копию платного расширения бесплатным аналогом с теми же возможностями, вынес архивы из открытой части и закрыл служебный вход снаружи.
- Сделал поисковый фундамент переезда: понятные адреса страниц, перенаправления со старых адресов на новые, разметка данных о компании и статьях для поисковиков, хлебные крошки, оглавления статей.
- Сдал работу с руководством администратора на 31 раздел с 40 скриншотами и отчётом заказчику — дальше сайт ведут без меня.
Итог
Было
- Сайт на конструкторе; начатый другой командой перенос застрял на полпути, тексты лендингов вшиты в код
- 41 плагин, нелицензионная копия платного расширения, архивы сайта скачиваются снаружи
- Любая правка текста — через разработчика
Стало
- Свой сайт: тексты и картинки девяти лендингов и главной правятся из админки
- 14 плагинов, лицензионно чистые расширения, архивы убраны, служебный вход закрыт
- Требования ТЗ по весу страницы выполнены с запасом больше чем вдвое
Плагинов на сайте стало 14 вместо 41, служебных расширений — 3 вместо 11; вместе с ними закрылась дыра, через которую сайтом можно было управлять снаружи. 2,23 ГБ архивов лежали в открытой части сайта и вынесены оттуда. Сервер отдаёт закэшированную страницу за 19 мс вместо 37. Страница укладывается в требования ТЗ с запасом больше чем вдвое: 526 КБ против лимита в 1,2 МБ. Сверка вёрстки с исходным макетом нашла 10 расхождений, ни одного критичного — все закрыты. Последняя волна доработок заказчика, 11 правок в 7 группах, завершена и проверена.
Переверстанный сайт сейчас работает на тестовом домене; выкат на боевой адрес — за заказчиком.
Технические детали
Решение и подход
Архитектура темы — классическая PHP-тема на Underscores (_s), сильно кастомизированная, на SCF. Ключевые инженерные решения:
- Реестр бандлов
route → bundle(inc/page-bundles.php+inc/enqueue.php): поэкранная загрузка CSS/JS, повторяющая исходные HTML 1:1 → выполнение требования ТЗ «JS по шаблонам, не глобально» и лимитов веса. - Гибрид-контент-модель (8B-2): библиотека ACF Flexible Content layout-ов с нулём fallback (контент только в БД), медиатека-пикер вместо путей, горизонтальные табы и группировка полей в редакторе — спроектировано под контент-команду без разработчика (источник:
docs/tasks/phase8-8b2-pilot-taxi-plan.md,docs/progress.md). - SEO без костылей (8C): URL без слеша сделан через ядро (
permalink_structure+redirect_canonical, 301 одним хопом), а не кастомным редиректором; schema — через фильтры Yoastwpseo_schema_*; переносимыйinc/seo.phpпод гардWPSEO_VERSION. - Кэш под shared-хостинг reg.ru (без Redis/LiteSpeed): WP Super Cache на mod_rewrite; root-cause за nginx-прокси — детект HTTPS через
X-Forwarded-Proto; security-заголовки в.htaccess(mod_headers), т.к. WPSC отдаёт кэш мимо PHP. - Безопасные миграции: client→case через swap
post_type(слаги/мета 1:1) + структурный 301-хук вinc/rewrites.php(плагин Redirection не подхватывал первое regex-правило); удаления — через draft+rename (корзина на сервере отключена).
Стек и обоснование
Ядро. WordPress 7.0 с классической PHP-темой, а не FSE: бэкенд предыдущей команды был рабочим, и стратегия «адаптировать, не пересобирать» требовала совместимости с ним, а ТЗ — контроля над ЧПУ и шаблонами, который в блочной теме достаётся дороже.
SCF вместо nulled ACF Pro. Замена снимает юридический и security-риск разом, а миграция обошлась без экспорта: SCF сохраняет API, поэтому field groups, объявленные в PHP, переехали как есть.
Формы и почта. Contact Form 7 с conditional-fields и honeypot, Flamingo для журнала заявок, FluentSMTP для доставки — формы должны были повторять эталонную вёрстку строго 1:1, и CF7 давал это без переписывания разметки.
SEO и кэш. Yoast SEO — ради JSON-LD и шаблонов мета-тегов, схема расширяется через фильтры wpseo_schema_*. WP Super Cache вместо предписанного ТЗ LiteSpeed: на shared-хостинге reg.ru нет ни LiteSpeed, ни Redis, замена согласована с заказчиком.
Фронт. Эталонные HTML/CSS/JS и vanilla app.js из dist, к ним Splide (карусели), GLightbox (лайтбокс), intl-tel-input (маска телефона, подключён локально), self-hosted variable-шрифт Golos Text, изображения в WebP/AVIF через <picture>.
Инструменты. WP-CLI и rsync-деплой, git локально без remote, Composer с phpcs/WPCS, @wordpress/scripts для eslint/stylelint, Playwright для визуального QA и пиксельной сверки с эталоном.
Инженерные вызовы
- Редактируемость «всего» без потери pixel-perfect — спроектирована библиотека из 58 переиспользуемых ACF Flexible Content layout-ов с вариантами hero/cta_form; ловушка:
instructionsACF выводятся сырым HTML — незакрытые теги-примеры ломали DOM редактора (решеноesc_html); top-level поля пер-страничных групп требуют префиксныхname/уникальных key (иначе репитеры не читались). - Окружение reg.ru как данность: нет Redis/LiteSpeed, Apache за nginx-прокси — кэш и security-заголовки пришлось решать через mod_rewrite/mod_headers и
X-Forwarded-Proto; статика отдаётся nginx-ом мимо.htaccess(заголовки на ассетах — тикет хостеру). - Yoast на staging:
WP_ENVIRONMENT_TYPE=stagingотключает canonical/indexables — потребовалась оговорка «на проде появится сам» + фильтр-гарантия/cases/. - Наследие предыдущей команды: обратный аудит дедупа экспертов (реальный контент был в «старых» записях, а не «новых»-заглушках); мёртвый плагин
smartway-tilda-fallbackс хардкод-путём прошлого автора; D1-миграция при отключённой корзине. - Регресс «пропала кнопка Обновить во всех Options» — ложно списан на роли 8E; реальная причина —
display:noneна колонке сабмита в admin-CSS (на SCF кнопка рендерится только в боковой колонке). Диагностика по view-source отделила клиентскую причину от серверной.
Услуги в проекте
- аудит
- доработка существующего
- миграция
- разработка
- деплой/DevOps
- SEO
- 152-ФЗ/ПДн (согласия)
- производительность/CWV
- контент-модель/редактируемость
- документация
- QA