Разработка трёхъязычного лендинга склада хранения колёс с админкой и зелёной зоной PageSpeed
Собственная тема WordPress без библиотек: заказчик правит контент и сниппеты сам, страница грузится за 102 КБ и держит 100 из 100 за скорость на мобильных.
Клиент
Отрасль
Услуги
Веб-сайт

Проблема
Склад сезонного хранения колёс под Варшавой принимает заявки в два коротких пика: весной и осенью, когда весь город переобувается одновременно. В сезон заказчик покупает рекламу, и лендинг для него — не визитка, а место, куда приходит оплаченный трафик. Прежний сайт был одноязычным, собирал заявки плохо и рекламировал услуги, которых у компании больше нет.
Два требования заказчика определили всю работу, и они тянут в разные стороны. Первое: он сам занимается SEO своего бизнеса и хотел править метатеги, тексты и цены без разработчика. Второе: сайт должен быть быстрым. На WordPress эти требования обычно конфликтуют — редактируемость приносят конструктор страниц, плагин форм и SEO-плагин со своими скриптами, и от зелёной зоны на мобильных ничего не остаётся. Задача была в том, чтобы получить оба, а не выбрать одно.
Задача
- Собрать одностраничный сайт на трёх языках: польском как основном, русском и английском
- Дать заказчику править контент, цены и метатеги всех трёх языков самому, в привычном интерфейсе
- Удержать зелёную зону PageSpeed на мобильных, где приходит рекламный трафик
- Собрать заявку так, чтобы она не терялась ни при отказе почты, ни при ошибке в скрипте
- Отсечь спам, не ставя между посетителем и заявкой ни одного лишнего барьера
- Настроить аналитику и пиксель так, чтобы рекламу можно было считать, не нарушая RODO
Результаты
- PageSpeed на мобильных: производительность 100, доступность 95, проверенные методы 100, SEO 100
- Проверка агентного просмотра пройдена полностью, 2 из 2 — страницу читают ассистенты, а не только браузер
- 102 КБ и восемь запросов на первую загрузку, ни одного стороннего запроса до согласия на куки
- Ни одной внешней библиотеки на фронте: без jQuery, без CSS-фреймворка, без иконочного шрифта, без шрифтов с чужого CDN
- Весь контент, цены, FAQ и метатеги трёх языков правятся заказчиком на одном экране админки
- Форма отправляет заявку и без JavaScript, а сама заявка всегда сохраняется в базу до всех уведомлений
- Спам отсекается без reCAPTCHA — без стороннего скрипта на каждой загрузке и без потери секунд загрузки
- Карта сайта содержит ровно три адреса: служебные архивы WordPress отдают 301 на главную
Проделанная работа
- Собственная классическая тема WordPress, написанная с нуля, без сборщика фреймворков и без jQuery
- Критический CSS инлайнится в head, остальной грузится неблокирующе с фолбэком для отключённого JavaScript
- Шрифты нарезаны собственными сабсетами, выбор файла делает unicode-range: кириллица на польской странице не скачивается никогда
- Изображения в AVIF с фолбэком в WebP, явные размеры против сдвигов вёрстки, приоритетная загрузка первого экрана
- Схема полей ACF зарегистрирована в PHP, а не накликана в интерфейсе: она версионируется и переносится копированием файла
- Настройки сайта вынесены на ту же страницу, что и контент, вторым блоком под редактором
- Три языка на Polylang с отдельными файлами контента и собственным правилом локализации полей для всех переводов главной
- Метатеги каждого языка заданы в теме и отдаются только тогда, когда поле в SEO-плагине пустое: значение заказчика всегда выигрывает
- Форма на двух путях — REST для браузеров со скриптами и обычная отправка формы для всех остальных, валидация одна
- Заявки хранятся как непубличный тип записи с колонками: телефон, размер, форма, дата
- Собственный антиспам: белый список полей, балльная оценка, подавление дублей, потолок уведомлений в час
- Уведомления на почту через SMTP с авторизацией и в мессенджер, оба — после ответа посетителю
- JSON-LD локального бизнеса и FAQ написан руками, диапазон цен считается из таблицы цен
- Аналитика и пиксель подключаются только после согласия, через простаивающий кадр браузера
Ключевые моменты проекта
Описание проекта
Заказчик сам занимается SEO: почему возможность править сниппеты была требованием
Обычно на сайте малого бизнеса метатеги правит тот, кто его сделал. Здесь наоборот: заказчик сам разбирается в поиске и хотел менять заголовки и описания сам, по ходу сезона, без письма разработчику и без ожидания.
Это требование звучит безобидно, но именно оно обычно и утяжеляет сайт. Редактируемость на WordPress приносят с собой конструктор страниц, плагин форм и SEO-плагин, у каждого свои стили и скрипты, и на мобильных от зелёной зоны ничего не остаётся. А второе требование заказчика было ровно про скорость.
Развязка в том, что редактируемость и вес — разные слои. Панель админки живёт на сервере и в браузер посетителя не попадает вообще. Тяжёлым сайт делает не возможность править, а способ, которым эту возможность обычно приносят. Поэтому поля собраны своей схемой, а на фронт не отдаётся ни одной строки чужого CSS.
Как метатеги и контент лендинга правятся в админке на одном экране
Метатеги каждого языка заданы в теме и уходят в страницу через фильтры SEO-плагина, но только когда соответствующее поле в плагине пустое. Заказчик правит в привычном месте, его значение всегда побеждает — и при этом каждый язык осмысленен с первого дня, а не показывает в выдаче служебное название страницы.
Всё остальное редактирование сведено на одну страницу. Разносить контент лендинга и его же настройки по двум экранам панели означает, что человек ищет телефон и адрес там, где их нет. Настройки — телефон, адрес, координаты, часы работы, почта для заявок, идентификаторы аналитики — переехали на ту же страницу вторым блоком под редактором.
Главные страницы трёх языков открываются в классическом редакторе намеренно. Блочный редактор складывает поля в свёрнутую панель у нижнего края экрана, и заказчик, открыв страницу, не увидел ни одного поля из полусотни. Классический редактор ставит их сразу под заголовком, где их и ищут.
Схема полей зарегистрирована в PHP, а не собрана кликами в интерфейсе. Разница в том, что такая схема версионируется вместе с темой, переносится на другой сервер копированием файла и не зависит от состояния базы.
Лендинг под сезонную рекламу: почему скорость здесь считается в стоимости клика
Хранение колёс — сезонный бизнес с двумя короткими пиками. В эти недели заказчик покупает рекламу, и это меняет цену медленной загрузки. На органическом трафике медленная страница стоит части посетителей. На платном она стоит части денег: визит уже оплачен, а человек уходит, не дождавшись первого экрана.
Отсюда и решения, которые иначе выглядели бы перфекционизмом. Ни одного стороннего запроса до согласия на куки — значит, ничего чужого между кликом по объявлению и первым экраном. Отсутствие капчи — значит, на пути к заявке нет ни оплаченной секунды загрузки, ни лишнего действия. Три языка на одном адресе — значит, на одну страницу можно вести три кампании на три разные аудитории.
Из чего складываются 102 КБ первой загрузки и восемь запросов
Первая загрузка страницы для гостя без куки согласия: HTML вместе с критическим CSS, встроенными иконками и микроразметкой — 34 КБ, отложенный CSS — 7 КБ, скрипт — 6 КБ, четыре файла шрифтов — 19 КБ, фотография первого экрана в AVIF — 37 КБ. Итого около 102 КБ и восемь запросов, ни одного к чужому домену.
Собрано это отказом, а не оптимизацией. На фронте нет jQuery, нет CSS-фреймворка, нет иконочного шрифта: четырнадцать иконок лежат в разметке как встроенные SVG. Из самого WordPress сняты эмодзи-скрипты, oEmbed, служебные метатеги и стили блочного редактора, которых на лендинге всё равно нет. Критический CSS инлайнится в head, остальной грузится неблокирующе и работает даже при отключённом JavaScript.
Порядок здесь именно такой: сначала не берём лишнее, потом сжимаем нужное. Оптимизация чужого набора библиотек даёт проценты, отказ от него — разы.
Шрифты лендинга, нарезанные своими сабсетами вместо стандартного набора
Стандартный расширенный латинский набор весит 31 КБ, а польскому языку нужны из него ровно восемь дополнительных букв. Собственный сабсет на этих буквах — 2 КБ.
Дальше работает unicode-range: браузер скачивает только тот файл, символы которого действительно встретились на странице. Кириллица на польской версии не загружается никогда, польские диакритики — на русской.
Отдельная деталь, которую стоило заметить заранее. У шрифта, выбранного для заголовков, кириллицы нет вообще — русская версия свалилась бы в системный шрифт уже после готовой вёрстки. Под тем же именем семейства кириллицу отдаёт ближайший геометрический гротеск, а какой файл взять, решает всё тот же unicode-range. Русская версия выглядит как остальные, а не как черновик.
Где на странице стоят кнопки и формы, чтобы заявка не зависела от одного экрана
Страница ведёт к одному действию — заявке на хранение комплекта, — и путей к нему сделано несколько, потому что люди приходят на разной стадии решения.
Форма стоит сразу после таблицы цен: человек узнал, сколько это стоит, и действие рядом, а не через четыре экрана. Второй экземпляр той же формы стоит ниже, после блоков, которые снимают возражения, — для тех, кто сначала дочитал. Телефон кликабельный и вынесен в шапку: часть аудитории не заполняет формы вообще и звонит, особенно с телефона.
Сама форма — два поля. Телефон и размер колёс, и всё. В списке размеров есть вариант «не знаю», потому что человек, который не помнит размер своих колёс, иначе просто закрывает страницу — а это как раз тот, кому склад нужнее всего.
Цены открыты таблицей, а не спрятаны за «уточняйте». Открытая цена отсеивает нецелевых до звонка и снимает главное возражение до формы. Той же работе служат блок про ошибки самостоятельного хранения и десять вопросов с ответами: они отвечают на то, что иначе прозвучало бы в разговоре и до заявки могло не дойти.
Это решения, а не измеренный результат: сезон впереди, и данных о конверсии по этой странице пока нет.
Три языка лендинга как три аудитории и три рекламные кампании на один адрес
Русская и английская версии написаны под своих читателей, а не переведены с польской. Английская объясняет, где Falenty Nowe относительно Варшавы, и прямо говорит, что писать можно по-английски: экспату трудно позвонить в польскоязычный сервис, и это его настоящее препятствие. Русская использует слова, которыми запрос задают в городе, — «переобувка» и «шиномонтаж», а не кальку с польского.
Тексты разложены по языковым файлам, где перевод накладывается на польскую основу: непереведённый ключ не даёт пустую секцию, а показывает польский вариант. Цены лежат только в польском файле и наследуются обоими переводами — одна цифра в одном месте, расходиться нечему.
Для рекламы это означает три кампании на три аудитории, ведущие на три адреса одной и той же страницы. Переключатель языков сделан без флагов: флаг обозначает страну, а не язык, и русский флаг на польском сайте несёт смысл, которого никто не заказывал.
Почему форма заявки лендинга работает без JavaScript и всегда пишет заявку в базу
У формы два пути: запрос к серверу из скрипта для браузеров, где скрипты работают, и обычная отправка формы для всех остальных. Валидация при этом одна. Дело не в доле посетителей с отключёнными скриптами — дело в том, что одна ошибка в скрипте не должна убивать единственную точку конверсии на странице, за трафик к которой заплачено.
Заявка всегда сохраняется в базу как отдельная запись с колонками: телефон, размер, из какой формы пришла, дата. В первой версии было «почта плюс мессенджер», и это означало: отвалится почта, заблокируют бота — заявка исчезнет бесследно.
Порядок операций переставлен после замера. Было: письмо, потом мессенджер, потом запись в базу, потом ответ посетителю — единственная копия заявки появлялась последней, после двух сетевых вызовов, и человек всё это время смотрел на крутящийся индикатор. Стало: запись в базу, ответ посетителю, уведомления следом. База не зависит от чужой сети, поэтому идёт первой.
Формат телефона намеренно не жёсткий. В Варшаву приезжают с украинскими, белорусскими и немецкими номерами, а маска польского формата такой номер просто не примет. Скрипт оставляет плюс и цифры и расставляет пробелы, но не отказывает.
Антиспам для формы из двух полей без reCAPTCHA и без потери клиентов
reCAPTCHA отвергнута по трём причинам сразу: чужой скрипт на каждой загрузке страницы, данные посетителей за пределами нашей инфраструктуры и минус к скорости, за которую боролись весь проект.
Вместо неё — модель угрозы под конкретную форму. В ней два поля, одно из которых список выбора. Свободного текста, ссылок и адресов почты нет, то есть обычному спаму просто некуда лечь. Реально опасны три вещи: подстановка своего значения в единственное текстовое поле, которое дойдёт до человека, лавина отправок и дубли.
Принцип, на котором всё построено: ничего не пропадает молча. Заявка сохраняется всегда, а оценка меняет только этикетку — уведомление уходит в любом случае, просто помеченное. Ложное срабатывание стоило бы клиента, а клиент дороже, чем один мусорный листок в списке.
Работает это так: белый список полей с жёсткой чисткой значений, балльная оценка по нескольким слабым сигналам, где ни один не срабатывает в одиночку, подавление дублей — тот же номер с тем же размером в течение получаса это второй клик, а не вторая заявка, — и потолок уведомлений в час, чтобы лавина не забила ящик. Подозрительные заявки получают метку и отдельный вид в списке.
Номера не проверяются по стране: «польский формат» отсекал бы живых клиентов, а их у склада под Варшавой заметная часть.
Согласие на куки по RODO, которое не мешает считать рекламу
Аналитика и пиксель подключаются только после явного согласия. Это требование RODO под маркетинговые куки, но здесь оно дало и технический выигрыш: инструменты проверки скорости приходят как чистый гость и этих скриптов не видят вовсе. Правильное юридическое решение оказалось заодно правильным техническим.
Предварительное соединение с чужими доменами сервер отдаёт только тем, у кого согласие уже есть. Для остальных заголовок страницы остаётся чистым.
Отказ сделан таким же доступным, как согласие: две равноценные кнопки, отказ стоит первым. Согласие, которое трудно не дать, добровольным не считается. В подвале есть кнопка отзыва согласия; если скрипты уже стартовали, страница перезагружается — выключить их на лету нельзя, и делать вид, что можно, нечестно.
Пока идентификаторы аналитики не заданы в админке, баннера нет вообще: спрашивать согласие не на что.
Политика приватности написана под этот сайт, а не скопирована: перечень собираемых данных сведён к тому, что форма действительно собирает, описано, что IP не сохраняется, а только хешируется для счётчика отправок. Три языковые версии закрыты от индексации, но ссылка на них из формы остаётся рабочей.
Микроразметка склада хранения колёс и вопросов, написанная руками вместо плагина
Разметка локального бизнеса и блока вопросов написана вручную: бесплатная версия SEO-плагина первое не отдаёт вовсе, а второе умеет только из собственных блоков, которых на этой странице нет. Диапазон цен в разметке считается из таблицы цен, поэтому вводить его руками и потом забывать обновить не приходится.
На проверке нашёлся конфликт: мой узел сайта шёл с тем же идентификатором, что и узел плагина — два разных определения под одним именем. Это не «больше данных», а противоречие. Свой узел убран, за плагином остались страница, хлебные крошки, сайт и организация, а мы добавляем только то, чего он не делает.
Отдельная работа — гигиена одностраничника. WordPress создаёт архивы автора, дат, категорий и меток: пустые страницы, которые поисковик проиндексирует, если найдёт. Все они отдают постоянный редирект на главную и исключены из карты сайта. В карте сайта ровно три адреса — по одному на язык.
Индексация управляется одним штатным переключателем в настройках. Первая версия определяла боевой домен автоматически, и заказчик справедливо это отклонил: переключатель, который сам меняет состояние после переезда, — это сюрприз в худший момент.
Что сделано, чтобы лендинг читали языковые модели, а не только поисковики
Часть решений на этой странице сделана в расчёте на то, что её будут пересказывать ассистенты, а не только показывать в выдаче. Проверка агентного просмотра проходит полностью, но дело не в галочке, а в том, из чего она складывается.
Цены лежат в настоящей таблице с заголовками строк и столбцов, а не в сетке из блоков: такую таблицу можно процитировать целиком. Адрес, часы работы и телефон стоят текстом в разметке, а не картинкой и не только внутри микроразметки. Ответы на вопросы лежат в документе даже в свёрнутом виде, поэтому доступны без выполнения скриптов. Заголовок на странице один, дальше строгая иерархия подзаголовков без пропусков уровней.
Вопросы сформулированы так, как их задают вслух: «от чего зависит цена», «нужно ли привозить самому», «храните ли вы шины без дисков». Ответы — по несколько предложений, с объяснением, а не одной строкой.
Пять ошибок в разработке лендинга и их настоящие причины
Самая полезная часть работы — не «сделал красиво», а «нашёл причину». Пять случаев, где симптом и причина оказались из разных мест.
Фотография первого экрана скачивалась в двух вариантах сразу и весила 269 КБ из 310 КБ всей страницы. Причина: размеры, объявленные в предзагрузке, не совпадали с размерами, объявленными в самой картинке, и браузер честно брал по одному файлу из каждого источника. Плюс скрытая правилом копия картинки скачивалась, чтобы никогда не показаться. После сведения обоих мест к одному источнику — 42 КБ.
Все иконки темы весили в десять–двадцать раз больше нормы, а фотографии — на несколько килобайт каждая. Причина оказалась не в сжатии: канал, которым файлы попадали на диск, дописывал в них метаданные о происхождении. Чистка на месте, у каждого формата своим способом — и у AVIF с правкой внутренних смещений, иначе файл ломается. Тринадцать иконок: 117 КБ превратились в 16 КБ.
Секции страницы исчезали ровно после того, как заказчик первый раз открыл и сохранил страницу. Причина: пустой повторяющийся блок полей возвращает одно значение до первого сохранения и другое после, а проверка на пустоту ловила только первое.
Человек, не знающий размер своих колёс, не мог отправить заявку. Вариант «не знаю» имел служебное значение, а чистильщик значений оставлял только буквы, цифры и дефисы — и превращал его в пустую строку. Ошибку внёс я сам часом раньше, когда ужесточал антиспам. Починено тем, что список размеров стал общим для формы и для проверки, а значения из прайса возвращаются дословно: прайс принадлежит клиенту, и фильтр не имеет права его править.
Человек, дважды опечатавшийся в номере, с третьего раза получал блокировку. Счётчик отправок считал все попытки, включая те, что не прошли проверку. Проверка и увеличение счётчика разведены: счётчик растёт только на принятых заявках.
Что осталось на стороне заказчика и хостинга
Список короткий и честный. Идентификаторы аналитики и пикселя вписываются в админке, код для этого не трогается. Ссылки на соцсети для подвала ждут самих ссылок, вёрстка под них готова. Политику приватности стоит показать юристу и подтвердить срок хранения заявок. Десять ответов на вопросы стоит прочитать хозяину бизнеса: часть деталей выведена из уже опубликованного на старом сайте и из отраслевой практики, и подтвердить их может только он.
Данных о конверсии пока нет — сезон впереди. Кейс о том, что построено и почему именно так, а не о том, что уже успело сработать.











