Календарь ретритов с мастером (retreatmaster.online)
Частный заказчик — проект о выездных ретритах с мастером и наставниками · Wellness / ретриты и духовные практики / онлайн-образование
Заказчик пришёл с восемью статичными страницами и заглушками вместо текстов. Сделал из них живой сайт, где всё содержимое правится из админки.
- PHP
- JavaScript
- HTML
- CSS
- WordPress
- SCF
- Fluent Forms
- адаптивная вёрстка
- MySQL
- Percona
- Memcached
- Schema.org/JSON-LD
- REST API
- Composer
- npm
- WPCS/PHPCS
- PHPStan
- ESLint
- Stylelint
- Playwright
В цифрах
- HTTP 200 на 16/16 endpoint'ов prod smoke-теста
- результат production-деплоя 2026-04-30
- ~6 965 строк PHP, ~1 924 строки CSS, 48 PHP-файлов темы
- объём кода кастомной темы retreat
- 6 CPT + 2 таксономии + 9 Options-страниц (root + 8 sub-pages), 14 SCF-файлов
- архитектура контента темы
- 17 CPT-записей + 7 SCF Options-страниц заполнены production-like контентом
- контент-фикстуры (Этап 8)
- phpcs (WPCS) 0 ошибок на каждом этапе
- соблюдение стандартов кода
- Полный аудит из 10 этапов (PHP/CSS/JS/БД/безопасность/перформанс/a11y/SEO/эталон/roadmap)
- пред-деплойный аудит
- WP root 176 MB, БД 3.85 MB, uploads 0 байт
- размеры миграции на прод
- Руководство администратора ~247 KB HTML
- пользовательская документация для заказчика
Ключевое
- Собрал структуру под сам предмет: ретриты, наставники, книги, онлайн-встречи и заявки — каждое со своими полями, а не универсальные страницы.
- Провёл аудит в десять этапов — безопасность, скорость, доступность, поиск — и закрыл находки кодом, а не списком рекомендаций.
- После выката на боевой сервер 16 проверок из 16 прошли успешно, и количество материалов совпало с тем, что было в разработке.
- Написал руководство администратора и чек-лист запуска — чтобы сайт можно было передать другому человеку и он разобрался.
Задача
Заказчику нужен был сайт-каталог выездных ретритов: сами поездки, наставники, книги, онлайн-встречи и форма заявки. Главное требование — вести всё это самому, без обращения к разработчику по каждому изменению даты или описания.
К началу работы существовала только статическая вёрстка из восьми страниц, причём с текстами-заглушками вместо настоящих. Это макет, а не сайт: посмотреть можно, добавить новый ретрит — нет.
Что сделано
- Перенёс восемь свёрстанных страниц в живой сайт, сохранив разметку и классы в неприкосновенности, — стили продолжили работать один в один, без переделки под движок.
- Собрал структуру под сам предмет, а не под универсальные страницы: ретриты, наставники, книги, онлайн-встречи и заявки — у каждого свой набор полей. Редактор заполняет форму, а не верстает текст.
- Сделал форму заявки в модальном окне: заявка сохраняется на сайте и уходит письмом, при необходимости — с копией наставнику. Заявка не теряется, даже если почта откажет.
- Провёл аудит в десять этапов — код, база, безопасность, скорость, доступность для людей с ограничениями, поисковая выдача — и закрыл находки кодом, а не списком рекомендаций заказчику.
- Выкатил на боевой сервер и написал руководство администратора с чек-листом запуска: сайт можно передать другому человеку, и он разберётся.
Итог
Сайт работает на retreatmaster.online. После выката 16 проверок из 16 прошли успешно, а количество материалов на боевом сервере совпало с тем, что было в разработке, — ничего не потерялось при переносе.
Заказчик ведёт сайт сам: добавляет ретриты и наставников, меняет даты и описания, видит заявки в админке. Руководство администратора и чек-лист запуска переданы вместе с сайтом.
Технические детали
Решение и подход
- Паттерн «контент в Options Pages» (по образцу arctic-m). Глобальный контент и контент уникальных страниц вынесен в SCF Options Pages с
tab-группировкой иdefault_valueиз исходной вёрстки; повторяющиеся сущности — в CPT с полями на самих записях. SCF (Secure Custom Fields) выбран вместо ACF Pro как API-совместимая бесплатная альтернатива (get_field,acf_add_local_field_group,acf_add_options_page). - Graceful degradation. Каждый шаблон проверяет
function_exists('get_field')и имеет__()-fallback, поля экранируются (esc_html/attr/url,wp_kses_post); секции управляются тогламиsection_*_visible. - Безопасность как код. Отдельные модули
inc/security-headers.php(HSTS/CSP-Report-Only/X-Frame-Options/Referrer-Policy/Permissions-Policy),inc/security-cleanup.php(скрытие генератора, отключение XML-RPC, ограничение REST user-enumeration), нонсы и capability-проверки в обработчиках форм. - SEO/Schema.
inc/seo.php(meta description, canonical, OpenGraph, Twitter Card) иinc/schema.php(JSON-LD: Organization, WebSite, Event, Person, Article, FAQPage); WP core sitemap. - SCF Local JSON. Field-группы синхронизируются в
acf-json/(версионирование + ускорение загрузки), при этом регистрируются и через PHP. - Деплой best-practice 2026. Поскольку медиабиблиотека пуста, а SCF-группы регистрируются кодом, миграция свелась к коду + БД (3.85 MB): rsync, импорт дампа,
wp search-replaceдомена, Memcached drop-in, security-заголовки, post-deploy backup на сервере.
Стек и обоснование
WordPress (classic theme, не FSE) — заказчику нужна редактируемость из админки без сборки. SCF вместо ACF Pro — тот же API, бесплатно. Fluent Forms Lite — формы заявок без платных аддонов. Vanilla CSS/JS (ES modules) без Tailwind/Sass/Vite — исходная вёрстка уже на чистом CSS, сборщик не нужен (и на проде нет Node). MySQL/Percona + Memcached — стек хостинга Timeweb. Тулинг качества: Composer (WPCS 3.x, PHPStan, WP-stubs), npm (@wordpress/eslint-plugin, Stylelint, Prettier). PHP 8.2+ с типизацией функций.
Инженерные вызовы
- Контент 1-в-1 для приёмки. Заказчик требовал идентичности с эталоном (Q-A.1) — написан импортёр
scripts/import-source.php(~51 KB), воспроизводящий placeholder'ы из 8 HTML-файлов на наполненных Options-страницах и CPT. - Маршрутизация заявок. Модалка передаёт data-атрибуты (mentor/retreat/meeting id, режим) в скрытые поля формы;
inc/mail-routing.phpслушаетfluentform/submission_inserted, создаёт CPTinquiry, пишет SCF/мету и шлёт письмо сReply-Toклиента и опц. CC наставнику. По ходу найден и исправлен баг с проверкой несуществующейfunction_exists('fluentform')→ helper черезshortcode_exists. - Расхождение окружений на проде. PHP CLI 8.2 vs заявленный web-PHP 8.4, устаревший Composer, отсутствие Node и cron только через панель Timeweb — обойдено стратегией «без сборки на проде» (vanilla) и ручным rsync+WP-CLI; зафиксировано в
prod-server-probe. - Безопасность поэтапно. HSTS с
max-age=300и CSP в режиме Report-Only — фазовый ввод с планом ramp-up (HSTS до года, CSP → enforce) в production-checklist, чтобы не сломать прод необратимыми заголовками.
Услуги в проекте
- разработка
- миграция
- аудит
- деплой
- SEO
- 152-ФЗ/ПДн
- контент
- документация
- поддержка