WordPress-разработчик: как показать сложный проект
Сложный WordPress-проект трудно показать: снаружи он выглядит как обычный сайт, а главные решения спрятаны в редакторе, плагинах, кеше, правах и процедуре релиза. Скриншот главной страницы не объяснит, почему команда не купила готовую тему, как сохранила редакторскую свободу и что произошло бы при сбое обновления. Кейс разработчика должен раскрыть архитектуру контента и жизненный цикл изменения.
Начните с редакционного контракта
Опишите пользователей админки. Контент-редактор собирает страницы из разрешённых блоков, маркетолог запускает landing, юрист обновляет обязательный текст, переводчик работает с локалями. У каждого разные права и вероятность ошибки. Зафиксируйте, что можно менять свободно, что ограничено design system и где требуется preview или approval.
Custom blocks оправданы не уникальным внешним видом, а устойчивой моделью контента. Блок «тариф» хранит название, цену, преимущества и CTA как поля; редактор не копирует произвольный HTML. Добавьте allowed combinations, inner blocks, responsive behavior и migration старой версии. Если содержание живёт только в serialised markup, изменение структуры может сломать сотни записей.
Выбирайте между core block, pattern, block variation, ACF и собственным Gutenberg block по реальной задаче. Pattern удобен для стартовой композиции, но после вставки копии расходятся. Dynamic block подходит данным, которые должны рендериться актуально. Серверный render не отменяет кеширование и escaping.
Лучший WordPress-кейс показывает, как редактор выпускает нужную страницу и при этом физически не может разрушить критический контракт.
В вакансиях WordPress-разработчиков ценится понимание редакционного продукта, а не только PHP hooks. Покажите короткое видео админского сценария рядом со схемой данных.
Разделите тему, плагины и внешние интеграции
Тема отвечает за presentation и шаблоны, domain plugin — за контентные типы и поведение, которое должно пережить смену темы. Интеграцию с CRM или платежами изолируйте адаптером и очередью повторов. Не складывайте всё в functions.php: там теряются границы тестирования, владения и загрузки.
| Слой | Ответственность | Проверка | Типичный риск |
|---|---|---|---|
| Theme | templates, styles, block presentation | visual и template tests | логика исчезает при смене темы |
| Domain plugin | types, permissions, business rules | unit и integration | глобальные hooks дают side effects |
| Integration | API, retries, mapping, webhook | contract и failure tests | дубль или потеря события |
| Operations | config, cache, deploy, backup | smoke и restore drill | «работает только на одном сервере» |
Плагинный выбор документируйте. Проверьте владельца, release cadence, security history, export path, multisite и нагрузку. Commodity-функцию разумно купить, но критическую бизнес-логику нельзя запирать в плагине без понятной миграции. Fork тоже создаёт долг обновлений.
Hooks регистрируйте узко. Admin-only код не должен грузиться на каждом frontend request; expensive query не запускается на init без необходимости. Укажите порядок sanitization, validation, authorization и escaping. Nonce защищает намерение запроса, но не заменяет capability check.
Докажите performance по слоям
Начните с waterfall и server timing. TTFB может расти из-за PHP, SQL, внешнего API или cold cache; LCP — из-за hero image, CSS, font и client script. Один общий Lighthouse score не указывает причину. Снимите baseline на cold и warm cache, авторизованном и публичном пользователе, ключевых templates.
Уберите N+1 и unbounded queries до установки ещё одного cache plugin. Используйте Query Monitor, slow log и application profiling. Для WP_Query ограничьте поля и pagination, проверьте indexes для meta-heavy модели или пересмотрите storage. Object cache помогает повторным reads, но не исправляет запрос, создающий огромный result set.
Контентный контракт проходит через blocks, domain plugins, performance и безопасный release.
Кеширование требует invalidation map. Изменение тарифа должно сбрасывать связанные страницы, API response и CDN tag, но не весь сайт. Укажите TTL, purge trigger и поведение при недоступном Redis. Stampede на популярной странице ограничивают lock, stale-while-revalidate или request coalescing.
Медиа готовьте при загрузке: размеры, modern formats, responsive srcset, ограничение исходников. Но не превращайте build в зависимость от внешнего mutable URL. Для third-party scripts задайте owner и budget; маркетинговый tag тоже может испортить LCP и privacy.
Покажите security как набор границ
Составьте threat model для ролей, загрузок, public forms, REST endpoints, webhooks и supply chain. Проверяйте capability на каждом privileged action, sanitise input по типу, escape на выводе по контексту. Prepared SQL не спасает от XSS, а escaping при записи усложняет повторное использование данных.
Upload обрабатывайте как недоверенный файл: MIME и расширение, размер, декодирование, хранение вне executable path, новые имена. Для webhook проверяйте подпись и freshness, затем обеспечьте idempotency. Ошибка повтора не должна создать второй заказ или письмо.
Обновления core и plugins проходят staging и smoke. SBOM или хотя бы реестр зависимостей помогает реагировать на advisory. Не редактируйте vendor plugin напрямую: patch исчезнет при update. Если временный fork неизбежен, зафиксируйте upstream version, diff и план выхода.
Установка security plugin сама по себе не задаёт модель защиты. В кейсе нужна конкретная граница, атака и проверенное поведение отказа.
Сравнивая зарплаты WordPress-разработчиков, отделяйте сборку страниц от ownership production-платформы. Performance, security, CI/CD и сложные интеграции заметно меняют уровень ответственности.
Опишите deploy и восстановление
Сборка должна быть воспроизводимой: lockfiles, versioned assets, environment config вне репозитория, миграции с явной версией. Контент и код живут разными циклами. Deploy не перетирает uploads и production database; config не копируется вручную по FTP.
Для database changes применяйте expand–migrate–contract. Сначала новый код читает старую и новую форму, затем backfill наблюдается и повторяется безопасно, позже старый путь удаляется. WordPress hooks при активации не подходят для долгой миграции на traffic request. Нужна CLI/job с progress и restart.
Release pipeline: backup или snapshot с проверяемым restore, maintenance strategy, deploy, cache warmup, smoke редактора и публичных templates, мониторинг ошибок, rollback. Rollback кода не всегда откатывает данные, поэтому опишите forward-fix и совместимость схемы.
Финальный артефакт кейса — incident или сложный release. Например, импорт каталога создал cache stampede; команда ввела chunking, idempotent cursor, tagged invalidation и нагрузочный сценарий. Покажите цифры до и после, но также failure path: что происходит при остановке job и как она продолжает без дублей. Так «сайт на WordPress» превращается в инженерный рассказ о надёжной контентной платформе.
Разверните этот incident в timeline. Import worker сохранил новую порцию товаров, очистил общий cache и начал следующую; сотни публичных запросов одновременно строили тяжёлые category pages. Первая реакция — увеличить Redis — не устраняла cold computation. Команда ввела cache tags на затронутые категории, stale-while-revalidate и lock с коротким ожиданием. Если rebuild падал, посетитель получал предыдущую версию с ограниченным TTL, а alert фиксировал возраст.
В decision log отметьте consistency. Цена товара не может оставаться stale столько же, сколько описание. Поэтому price fragment получил отдельный короткий cache и purge после подтверждённой записи, а editorial copy сохранил длинный TTL. Разделение уменьшило нагрузку без нарушения коммерческого контракта.
Покажите restore drill. На staging восстановили database и uploads из согласованной точки, затем проверили media references, редакторские роли, cron и внешние webhooks. Выяснилось, что secrets и rewrite rules не входили в резервную процедуру. Их не стали класть в backup с контентом: добавили инфраструктурный manifest, отдельное secret recovery и автоматический smoke. Такой разбор доказывает восстановление, а не только наличие архивного файла.
Для сложной миграции приложите progress schema: version, cursor, processed, failed, checksum и last heartbeat. Повтор job читает cursor и повторно обрабатывает последнюю порцию идемпотентно. Редактор в это время видит статус, но не может запустить второй конфликтующий импорт. Здесь встречаются code quality, UX и operations — именно то, что отличает production ownership.
Security failure path поставьте рядом с release: checksum или данные о происхождении plugin update расходятся с одобренным release, pipeline блокирует artifact и сохраняет текущую версию. Команда проверяет advisory и выбирает patched release либо временную изоляцию feature, не редактируя production вручную.
В отчёте сохраняются версия, источник пакета, причина блока и владелец повторной проверки; иначе похожий alert снова придётся расследовать с нуля.