18

Как превратить сильную статическую верстку в живой WordPress-сайт

11.04.2026 13 мин чтения



Хорошая статическая верстка часто создает опасную иллюзию: кажется, что почти все уже сделано, и осталось лишь аккуратно перенести HTML в тему. На практике именно в этот момент проект обычно и начинает расползаться. Одни секции теряют ритм, другие наследуют старые стили, третьи живут отдельно от контента, а редактор WordPress постепенно превращается в компромисс между “почти как в макете” и “ну так тоже работает”.

Эта статья о другом пути. О том, как взять сильную статику, не потерять ее характер в WordPress, выстроить вокруг нее блоковую систему, подключить контентную модель, включить WP-CLI в повседневный workflow и в итоге получить не просто красивую обложку, а рабочий, поддерживаемый сайт.

Финальная главная страница WordPress-сайта после пересборки
Финальная главная страница: тот момент, когда уже видно не просто красивый экран, а цельную систему сайта.

Когда статическая верстка уже почти продукт

У этого проекта было редкое преимущество: отправной точкой стала не одна красивая главная страница, а целый комплект экранов в папке site/. Это важная разница. Если у вас есть только hero и пара декоративных секций, вы пока работаете с внешним впечатлением. Если у вас есть вся система страниц, вы уже работаете с продуктовой структурой.

Внутри статики были собраны главная, страницы услуг, страницы “о специалисте”, контакты, блог, статья блога, портфолио и кейс. Это сразу задавало правильный масштаб задачи: WordPress должен был воспроизвести не одну обертку, а весь ритм проекта.

Статическая главная страница из папки site
Статическая главная страница из site/. Уже здесь виден тон проекта: крупная типографика, темный hero, спокойная светлая база и продуманная последовательность секций.
Статическая страница о специалисте из папки site
Статическая внутренняя страница показывает, что проект изначально мыслился как система, а не как единственный продающий экран.

Это и стало первым сильным правилом проекта: главным эталоном является не CMS и не текущая база, а папка site/. Все последующие решения приходилось сверять именно с ней:

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

Это звучит просто, но именно эта дисциплина потом спасает проект от бесконечного числа “почти удачных” решений.

Правила, которые удержали проект от расползания

Почти сразу стало ясно, что без четких правил WordPress очень быстро начнет подстраивать проект под себя, а не наоборот. Поэтому работа держалась на нескольких простых, но жестких принципах.

  1. Статика из site/ остается главным эталоном по структуре.
  2. Идентичность сайта нельзя терять или размывать.
  3. Внешний референс нужен только для усиления доверия и подачи, а не для копирования.
  4. Все важные расхождения нужно искать в реальной разметке и реальном фронтенде, а не в абстрактных предположениях.
  5. Контент и данные должны жить в WordPress как нормальная модель, а не как случайные HTML-вставки.

Один из самых полезных промптов в таком проекте звучит примерно так:

Есть действующий WordPress-сайт визитки. Нужно полностью перевести его на новую верстку из папки `site/`.

Сохраняем идентичность проекта:
- `Имя`;
- `Домен`;
- специализация на `1С-Битрикс` и `WordPress`.

`site/` считаем главным эталоном по структуре, ритму и составу секций. Где нужно, интеграцию можно улучшать, но нельзя без причины уходить от верстки.

Сначала составь карту будущих блоков и расхождений, а затем переходи к реализации.

Хорошая постановка задачи здесь решает не меньше, чем хороший CSS. Она не дает проекту расплыться еще до первого коммита.


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

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

В этом проекте базой стал theme.json. Он зафиксировал палитру, контейнеры, типографику и общие настройки редактора.

{
  "settings": {
    "color": {
      "palette": [
        { "slug": "primary", "color": "#101826", "name": "Primary" },
        { "slug": "cta", "color": "#C9A36C", "name": "CTA" },
        { "slug": "background", "color": "#F6F1E8", "name": "Background" },
        { "slug": "deep", "color": "#09111D", "name": "Deep" }
      ]
    },
    "layout": {
      "contentSize": "1280px",
      "wideSize": "1440px"
    },
    "typography": {
      "fontFamilies": [
        { "name": "Fraunces", "slug": "heading", "fontFamily": "'Fraunces', serif" },
        { "name": "Manrope", "slug": "body", "fontFamily": "'Manrope', sans-serif" }
      ]
    }
  }
}

Это важный момент: контейнер и типографика были перенесены в тему как правило, а не как случайный набор CSS-чисел. Именно поэтому позже можно было честно говорить “размеры контейнера и заголовков больше не трогаем” — потому что они уже были зафиксированы в системном слое.

Поверх этого тема взяла на себя фронтенд-ассеты, иконки, анимации и рабочие скрипты.

add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style(
        'portfolio-design-system',
        portfolio_asset_uri('css/design-system.css'),
        ['portfolio-tailwind'],
        portfolio_asset_version('css/design-system.css')
    );

    wp_enqueue_script(
        'portfolio-main',
        portfolio_asset_uri('js/main.js'),
        ['portfolio-lucide', 'portfolio-alpine'],
        portfolio_asset_version('js/main.js'),
        true
    );

    wp_localize_script('portfolio-main', 'portfolioData', [
        'ajaxUrl' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('portfolio_nonce'),
    ]);
});

На этом шаге WordPress перестал быть просто оболочкой поверх HTML и начал работать как настоящая среда проекта. Тема стала отвечать не только за внешний вид, но и за целостность поведения.

Почему блоковую систему пришлось пересобирать почти с нуля

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

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

  • header и footer;
  • hero;
  • услуги, процесс, FAQ, CTA;
  • портфолио и блоговые сетки;
  • контактные блоки;
  • специализированные секции для кейсов.

Регистрация блоков была собрана через единый контракт:

add_action('init', function () {
    $blocks_dir = BLOCKS_PORTFOLIO_PATH . 'build';
    $blocks = glob($blocks_dir . '/*/block.json');

    if ($blocks === false) {
        return;
    }

    foreach ($blocks as $block_json) {
        register_block_type_from_metadata($block_json);
    }
});

А список entry points отражал уже не абстрактные “виджеты”, а реальные страницы и сценарии сайта:

entry: {
    'header/index': path.resolve(__dirname, 'src/header/index.js'),
    'footer/index': path.resolve(__dirname, 'src/footer/index.js'),
    'hero/index': path.resolve(__dirname, 'src/hero/index.js'),
    'services/index': path.resolve(__dirname, 'src/services/index.js'),
    'portfolio-grid/index': path.resolve(__dirname, 'src/portfolio-grid/index.js'),
    'process/index': path.resolve(__dirname, 'src/process/index.js'),
    'blog-grid/index': path.resolve(__dirname, 'src/blog-grid/index.js'),
    'case-study-results/index': path.resolve(__dirname, 'src/case-study-results/index.js')
}

Особенно полезным оказался общий editor-layer. Вместо того чтобы вручную собирать настройки каждого блока, проект опирался на shared-редактор, который читал block.json, поднимал controls и сразу показывал серверный preview.

export function registerServerBlock(metadata) {
    registerBlockType(metadata.name, {
        ...metadata,
        edit: ({ attributes, setAttributes }) => (
            <>
                <BlockInspector
                    metadata={metadata}
                    attributes={attributes}
                    setAttributes={setAttributes}
                />
                <div className="portfolio-block-editor__preview">
                    <ServerSideRender block={metadata.name} attributes={attributes} />
                </div>
            </>
        ),
        save: () => null,
    });
}

Именно так WordPress начал работать не как “редактор страницы”, а как редактор собственной библиотечной системы.

Страница о специалисте в WordPress после пересборки блоков
После пересборки библиотека блоков начала удерживать не только внешний стиль, но и ритм внутренних страниц.

Хороший промпт для такого этапа обычно выглядит так:

Давай пересоберем блоковую систему заново.

Удали старые кастомные блоки как источник архитектурного хвоста и собери новый набор блоков в соответствии с реальной структурой страниц из `site/`.

Требования:
- блоки должны быть серверными;
- `block.json`, `index.js`, `render.php`, `style.scss`, `editor.scss` идут как единый стандарт;
- структура блоков должна отражать реальные секции сайта;
- редактор должен использовать единый shared-layer.

Как статические страницы превратились в систему шаблонов

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

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

  • hero;
  • основные направления;
  • процесс работы;
  • темная секция “что входит”;
  • FAQ;
  • финальный CTA.

Когда это разложено по шагам, уже намного проще поймать лишние или недостающие блоки.

Статическая страница услуг из папки site
Статическая страница услуг задает правильный порядок секций и нужный визуальный ритм.
Страница услуг в WordPress после выравнивания по структуре
Версия в WordPress после выравнивания по составу секций. Здесь особенно хорошо видно, зачем нужна честная сверка со статикой.

Главная страница тоже собиралась именно как последовательность секций, а не как разрозненный набор блоков:

<!-- wp:template-part {"slug":"header","tagName":"div"} /-->
<main class="wp-block-group site-main">
    <!-- wp:portfolio/hero {"variant":"home", ... } /-->
    <!-- wp:portfolio/tech-stack {"sectionKicker":"Формат работы", ... } /-->
    <!-- wp:portfolio/services /-->
    <!-- wp:portfolio/portfolio-grid {"postsPerPage":3} /-->
    <!-- wp:portfolio/process {"sectionKicker":"Процесс", ... } /-->
    <!-- wp:portfolio/cta {"sectionKicker":"Старт работы", ... } /-->
</main>
<!-- wp:template-part {"slug":"footer","tagName":"div"} /-->

Обратите внимание на маленькую, но важную деталь: header и footer подключаются как tagName: "div". Для этого проекта это оказалось не мелочью, а частью реального бага: именно лишняя семантическая обертка и top-level block-gap в какой-то момент давали светлую полосу над hero.

Зачем проекту понадобились WP-CLI, кейсы и своя контентная модель

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

Поэтому в проекте появились:

  • project как отдельный тип записи;
  • таксономия tech_stack;
  • поля для challenge, solution, results, screenshots и testimonial;
  • WP-CLI как обычный рабочий инструмент, а не запасной сценарий.
function portfolio_register_project_cpt()
{
  $args = array(
    'public' => true,
    'rewrite' => array('slug' => 'portfolio'),
    'has_archive' => true,
    'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
    'show_in_rest' => true,
  );

  register_post_type('project', $args);
}
function portfolio_register_tech_stack_taxonomy()
{
  $args = array(
    'hierarchical' => false,
    'public' => true,
    'show_in_rest' => true,
    'rewrite' => array('slug' => 'tech'),
  );

  register_taxonomy('tech_stack', array('project'), $args);
}

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

$wpArgs = $args
$wpCliPhar = '/var/www/evgslesar/data/www/slesarweb.ru/wp-content/mu-plugins/.tools/wp-cli.phar'

docker compose exec -T wordpress php $wpCliPhar --allow-root --path=/var/www/html @wpArgs
powershell -ExecutionPolicy Bypass -File .\wp.ps1 cli info
powershell -ExecutionPolicy Bypass -File .\wp.ps1 option get home
powershell -ExecutionPolicy Bypass -File .\wp.ps1 post list --post_type=page --fields=ID,post_name,post_title,post_status --format=table
powershell -ExecutionPolicy Bypass -File .\wp.ps1 post list --post_type=project --fields=ID,post_name,post_title,post_status --format=table

Это не просто “удобно”. Это меняет характер проекта. Сайт становится воспроизводимым: его можно проверить, пересобрать, наполнить и довести без ручной суеты.

Архив портфолио в WordPress
Архив проектов показывает, зачем понадобился отдельный тип записи: кейсы перестают быть случайными страницами и становятся самостоятельным слоем сайта.
Статическая страница кейса из папки site
Статический кейс задает будущую структуру страницы проекта: summary, challenge, solution, screenshots и results.
Страница кейса в WordPress
Кейс в WordPress после интеграции: важный пример того, что сайт масштабируется за пределы лэндинговой логики.

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

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

От внешнего ориентира в проект стоит забирать не идентичность, а принципы:

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

Вот почему хороший промпт про внешний референс должен звучать осторожно:

Используй `Референс-сайт` только как источник вдохновения по подаче доверия и официальности.

Нельзя копировать идентичность, стиль формулировок и контент буквально.

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

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

Страница блога в WordPress
Блог в итоговой версии сайта работает не как случайная лента постов, а как часть общей профессиональной упаковки.
Страница контактов в WordPress
Контактная страница стала местом не только для формы, но и для доверия: понятный процесс старта, официальный формат работы и организационная ясность.

Пять багов, которые сделали решение лучше

Самая полезная часть этой истории — не только то, что получилось, но и то, что по пути ломалось. Именно на таких вещах WordPress-проект перестает быть “переносом шаблона” и начинает становиться инженерной системой.

1. Заголовки hero теряли видимость

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

2. Светлая полоса сверху была не про hero, а про разметку

Сначала все выглядело как обычный CSS-баг. На деле причина оказалась в structure-level вещи: лишняя обертка вокруг template-part и top-level block-gap. Это хороший урок: если визуальный симптом слишком странный, нужно смотреть в DOM, а не продолжать крутить отступы.

3. Header оказался самым длинным хвостом полировки

Мобильная кнопка была видна на десктопе, потом site-header__bar нужно было фиксировать, потом поднимать по z-index, потом сдвигать breakpoint. Header почти всегда выглядит “простым” блоком только до тех пор, пока вы не начинаете сводить адаптив, реальное меню и фиксированное позиционирование.

4. Счетчики на странице about оставались по нулям

Даже мелкий счетчик — это не украшение, а часть поведения. Ему нужен fallback. В этом проекте числа пришлось защищать не только анимацией, но и безопасной подстановкой значений.

5. Форма контактов сначала рендерилась без нормальных стилей

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

Мини-галерея ключевых экранов

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

Статическая страница портфолио
Статическая страница портфолио.
Статическая страница блога
Статическая страница блога.
Статическая страница контактов
Статическая страница контактов.
Страница о специалисте в WordPress
WordPress-версия страницы “о специалисте”.
Страница услуг в WordPress
WordPress-версия страницы услуг.

Итоговая схема проекта

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

site/
  ├─ index.html
  ├─ about.html
  ├─ services.html
  ├─ contact.html
  ├─ portfolio.html
  ├─ blog.html
  └─ case-study.html

themes/portfolio/
  ├─ theme.json
  ├─ functions.php
  ├─ assets/
  └─ templates/

plugins/blocks-portfolio/
  ├─ blocks-portfolio.php
  ├─ webpack.config.js
  ├─ src/_shared/
  └─ src/{block-name}/

mu-plugins/
  └─ portfolio-general.php

wp.ps1

Если перевести это на человеческий язык, получится так:

  • статическая папка задает эталон;
  • тема держит дизайн-систему и поведение;
  • плагин блоков собирает библиотеку секций;
  • mu-plugin отвечает за доменную модель;
  • WP-CLI делает структуру и контент воспроизводимыми;
  • а реальный фронтенд постоянно проверяет, не ушел ли проект от своей исходной силы.

Как повторить такой подход в другом проекте

Если обобщить всю эту историю до практического маршрута, получится довольно ясная последовательность.

  1. Не начинайте с CMS. Сначала соберите полноценную статическую систему экранов.
  2. Зафиксируйте правила: что является эталоном, что можно менять, а что нельзя.
  3. Перенесите дизайн-систему в тему через theme.json, глобальные стили и нормальный enqueue-слой.
  4. Не тащите хвост старой блоковой архитектуры, если она мешает. Пересоберите библиотеку секций честно.
  5. Сводите страницы не по впечатлению, а по составу секций.
  6. Выносите кейсы, таксономии и мета в отдельную контентную модель, как только это становится оправдано.
  7. Подключайте WP-CLI в рабочий процесс как можно раньше.
  8. Берите от внешних референсов только принципы, а не чужую личность.
  9. И главное: проверяйте результат на живом фронтенде, потому что именно там всплывают настоящие проблемы.

В этом и состоит главный вывод статьи. Сильный WordPress-сайт рождается не из удачного hero-экрана и не из красивого набора блоков. Он рождается тогда, когда статика, тема, блоки, контентная модель и реальный пользовательский сценарий начинают работать как одна система.

Евгений Слесаренко
Автор

Евгений Слесаренко

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