Files

122 KiB
Raw Permalink Blame History

Экспертный портал БИТ.WMS — План реализации

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Создать экспертный контентный портал по складской логистике на WordPress с фокусом на лидогенерацию для компании "Первый Бит".

Architecture: WordPress 6.x + GeneratePress Premium (дочерняя тема) + GenerateBlocks Pro. Контент управляется через CPT + ACF Pro. Фиксированная боковая навигация (как place.lemma.ru), строгое соответствие брендбуку "Первый Бит" (розовый/чёрный/белый, Suisse Int'l). Лидогенерация: формы Contact Form 7, JivoSite, callback, попапы, gated-контент.

Tech Stack: WordPress 6.x, GeneratePress Premium, GenerateBlocks Pro, ACF Pro, Contact Form 7, Popup Maker, Yoast SEO, PHP 8.x, MySQL, CSS3, vanilla JS.

Спецификация: docs/superpowers/specs/2026-04-03-bit-wms-site-design.md


Файловая структура проекта

wp-content/
├── themes/
│   └── bitwms-child/                  # Дочерняя тема GeneratePress
│       ├── style.css                  # Мета + кастомные стили брендбука
│       ├── functions.php              # Подключение модулей
│       ├── inc/
│       │   ├── cpt.php                # Регистрация кастомных типов записей
│       │   ├── acf-fields.php         # ACF-группы полей (экспорт PHP)
│       │   ├── ajax-filter.php        # AJAX-фильтрация ленты на главной
│       │   └── enqueue.php            # Подключение шрифтов, скриптов
│       ├── templates/
│       │   ├── sidebar-nav.php        # Фиксированная боковая панель
│       │   ├── hero.php               # Герой главной страницы
│       │   ├── content-card.php       # Карточка контента (универсальная)
│       │   ├── section-filter.php     # Блок фильтрации по рубрикам
│       │   ├── section-promo-wms.php  # Промо-блок БИТ.WMS
│       │   ├── section-subscribe.php  # Блок подписки на рассылку
│       │   └── section-clients.php    # Блок "Наши клиенты"
│       ├── template-parts/
│       │   ├── single-case.php        # Детальная страница кейса
│       │   ├── single-webinar.php     # Детальная страница вебинара
│       │   ├── single-course.php      # Детальная страница курса
│       │   ├── single-event.php       # Детальная страница мероприятия
│       │   └── single-material.php    # Детальная страница материала
│       ├── page-templates/
│       │   ├── front-page.php         # Шаблон главной страницы
│       │   ├── page-bit-wms.php       # Шаблон страницы БИТ.WMS
│       │   ├── page-contacts.php      # Шаблон страницы контактов
│       │   └── page-anketa.php        # Шаблон анкеты для детального запроса
│       ├── archive/
│       │   └── archive-cpt.php        # Единый шаблон архива для CPT
│       ├── js/
│       │   ├── sidebar-nav.js         # Логика боковой панели (hover, мобильные)
│       │   ├── ajax-filter.js         # AJAX-фильтрация + "Показать ещё"
│       │   └── gated-content.js       # Модальное окно gated-контента
│       ├── fonts/
│       │   ├── SuisseIntl-Bold.woff2
│       │   └── SuisseIntl-Book.woff2
│       └── img/
│           ├── logo.svg               # Логотип "первыйБит"
│           ├── logo-short.svg         # Сокращённый логотип для боковой панели
│           └── icons/                 # SVG-иконки для навигации
│               ├── warehouse.svg
│               ├── folder.svg
│               ├── document.svg
│               ├── camera.svg
│               ├── graduation.svg
│               ├── calendar.svg
│               ├── download.svg
│               ├── bell.svg
│               └── phone.svg

Task 1: Установка WordPress и базовая настройка

Контекст: Поднимаем локальную среду разработки, устанавливаем WordPress и необходимые плагины. Это фундамент для всей последующей работы.

Файлы:

  • Создать: конфигурация локальной среды (Local by Flywheel / Docker / MAMP)

  • Step 1: Установить WordPress локально

Используем Local by Flywheel (рекомендуется для простоты) или Docker. Создаём сайт:

  • Имя сайта: bitwms-local
  • PHP: 8.2
  • Web Server: nginx
  • MySQL: 8.0
# Если используем wp-cli с уже установленным WordPress:
wp core download --locale=ru_RU
wp config create --dbname=bitwms --dbuser=root --dbpass=root --locale=ru_RU
wp db create
wp core install --url="http://bitwms.local" --title="БИТ.WMS — Экспертный портал" --admin_user=admin --admin_password=admin --admin_email=admin@bitwms.local
  • Step 2: Установить и активировать обязательные плагины
# Премиум-плагины устанавливаются вручную (загрузка zip через админку):
# - GeneratePress Premium (лицензия)
# - GenerateBlocks Pro (лицензия)
# - ACF Pro (лицензия)

# Бесплатные плагины через wp-cli:
wp plugin install generatepress --activate
wp plugin install contact-form-7 --activate
wp plugin install popup-maker --activate
wp plugin install wordpress-seo --activate

# Удалить дефолтные плагины:
wp plugin delete akismet hello
  • Step 3: Базовые настройки WordPress
# Постоянные ссылки: /%postname%/
wp rewrite structure '/%postname%/'

# Часовой пояс, формат дат
wp option update timezone_string 'Asia/Yekaterinburg'
wp option update date_format 'd.m.Y'
wp option update time_format 'H:i'

# Отключить комментарии
wp option update default_comment_status 'closed'
wp option update default_ping_status 'closed'

# Удалить дефолтный контент
wp post delete 1 --force
wp post delete 2 --force
wp post delete 3 --force

# Настройки чтения: статическая главная страница
wp post create --post_type=page --post_title='Главная' --post_status=publish
wp post create --post_type=page --post_title='Блог' --post_status=publish
wp option update show_on_front 'page'
wp option update page_on_front $(wp post list --post_type=page --name=главная --field=ID)
wp option update page_for_posts $(wp post list --post_type=page --name=блог --field=ID)
  • Step 4: Активировать GeneratePress Premium модули

В админке WordPress: Appearance > GeneratePress > активировать модули:

  • Typography

  • Colors

  • Spacing

  • Blog

  • Elements

  • WooCommerce (не нужен, оставить выкл.)

  • Menu Plus

  • Sections (не нужен при использовании GenerateBlocks)

  • Disable Elements

  • Copyright

  • Background Images

  • Step 5: Проверить что всё работает

Открыть http://bitwms.local — должен отобразиться чистый сайт GeneratePress с русской локалью, статической главной страницей.

  • Step 6: Инициализировать git-репозиторий
cd /path/to/wordpress/wp-content
git init
cat > .gitignore << 'EOF'
# WordPress core — не трекаем
../../*.php
../../wp-admin/
../../wp-includes/

# Плагины — премиум устанавливаются отдельно
plugins/

# Загрузки
uploads/

# Системное
.DS_Store
Thumbs.db
*.log

# Трекаем только дочернюю тему
!themes/bitwms-child/
EOF

git add .
git commit -m "init: WordPress project structure"

Task 2: Дочерняя тема — создание и подключение шрифтов

Контекст: Создаём дочернюю тему GeneratePress с брендбуком "Первый Бит". Шрифт Suisse Int'l — коммерческий, файлы woff2 должны быть предоставлены (или временно используем Arial как fallback).

Файлы:

  • Создать: wp-content/themes/bitwms-child/style.css

  • Создать: wp-content/themes/bitwms-child/functions.php

  • Создать: wp-content/themes/bitwms-child/inc/enqueue.php

  • Step 1: Создать дочернюю тему

Создать файл wp-content/themes/bitwms-child/style.css:

/*
 Theme Name: БИТ.WMS Portal
 Theme URI: https://wms.ru
 Description: Дочерняя тема GeneratePress для экспертного портала БИТ.WMS
 Author: Первый Бит
 Author URI: https://1bit.ru
 Template: generatepress
 Version: 1.0.0
 Text Domain: bitwms
*/

/* ==========================================================================
   Брендбук "Первый Бит" — CSS Custom Properties
   ========================================================================== */

:root {
    /* Цвета */
    --color-primary: #E50071;       /* Розовый/маджента — Pantone 213 */
    --color-black: #000000;         /* Заголовки, текст */
    --color-white: #FFFFFF;         /* Основной фон */
    --color-gray-light: #EBEBEB;    /* Дополнительный */
    --color-gray-text: #666666;     /* Мета-текст */

    /* Типографика */
    --font-heading: 'Suisse Intl', Arial, sans-serif;
    --font-body: 'Suisse Intl', Arial, sans-serif;

    /* Лейаут */
    --sidebar-width-collapsed: 70px;
    --sidebar-width-expanded: 250px;
    --content-max-width: 1200px;
    --header-height: 60px;
}

/* ==========================================================================
   @font-face — Suisse Int'l (файлы в fonts/)
   Если шрифты недоступны, fallback на Arial (по брендбуку)
   ========================================================================== */

@font-face {
    font-family: 'Suisse Intl';
    src: url('./fonts/SuisseIntl-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Suisse Intl';
    src: url('./fonts/SuisseIntl-Book.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* ==========================================================================
   Глобальные стили
   ========================================================================== */

body {
    font-family: var(--font-body);
    font-weight: 400;
    color: var(--color-black);
    background-color: var(--color-white);
    margin: 0;
    padding: 0;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
    font-weight: 700;
    color: var(--color-black);
    line-height: 1.2;
}

h1 { font-size: 3rem; }
h2 { font-size: 2.25rem; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }

a {
    color: var(--color-primary);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* ==========================================================================
   Кнопки
   ========================================================================== */

.btn {
    display: inline-block;
    padding: 12px 32px;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1rem;
    line-height: 1.5;
    text-decoration: none;
    border-radius: 0;
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
    border: 2px solid transparent;
}

.btn-primary {
    background-color: var(--color-primary);
    color: var(--color-white);
    border-color: var(--color-primary);
}

.btn-primary:hover {
    background-color: #C60060;
    border-color: #C60060;
    text-decoration: none;
    color: var(--color-white);
}

.btn-outline {
    background-color: transparent;
    color: var(--color-black);
    border-color: var(--color-black);
}

.btn-outline:hover {
    background-color: var(--color-black);
    color: var(--color-white);
    text-decoration: none;
}

/* ==========================================================================
   Утилиты
   ========================================================================== */

.container {
    max-width: var(--content-max-width);
    margin: 0 auto;
    padding: 0 24px;
}

.badge {
    display: inline-block;
    padding: 4px 12px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    background-color: var(--color-gray-light);
    color: var(--color-black);
}
  • Step 2: Создать functions.php дочерней темы

Создать файл wp-content/themes/bitwms-child/functions.php:

<?php
/**
 * БИТ.WMS Portal — дочерняя тема GeneratePress
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

// Подключение стилей родительской темы
add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style(
        'generatepress-parent',
        get_template_directory_uri() . '/style.css'
    );
    wp_enqueue_style(
        'bitwms-child',
        get_stylesheet_uri(),
        ['generatepress-parent'],
        wp_get_theme()->get('Version')
    );
});

// Подключение модулей
$bitwms_includes = [
    'inc/enqueue.php',
];

foreach ($bitwms_includes as $file) {
    $filepath = get_stylesheet_directory() . '/' . $file;
    if (file_exists($filepath)) {
        require_once $filepath;
    }
}
  • Step 3: Создать inc/enqueue.php

Создать файл wp-content/themes/bitwms-child/inc/enqueue.php:

<?php
/**
 * Подключение скриптов и стилей
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

add_action('wp_enqueue_scripts', function () {
    $theme_version = wp_get_theme()->get('Version');
    $theme_uri = get_stylesheet_directory_uri();

    // Боковая навигация
    wp_enqueue_script(
        'bitwms-sidebar-nav',
        $theme_uri . '/js/sidebar-nav.js',
        [],
        $theme_version,
        true
    );
}, 20);
  • Step 4: Создать placeholder для JS боковой навигации

Создать файл wp-content/themes/bitwms-child/js/sidebar-nav.js:

/**
 * Боковая навигация — hover-раскрытие и мобильный гамбургер
 */
document.addEventListener('DOMContentLoaded', function () {
    const sidebar = document.querySelector('.sidebar-nav');
    const hamburger = document.querySelector('.hamburger-toggle');
    const body = document.body;

    if (!sidebar) return;

    // Мобильное меню — toggle
    if (hamburger) {
        hamburger.addEventListener('click', function () {
            sidebar.classList.toggle('sidebar-nav--open');
            body.classList.toggle('sidebar-overlay');
        });
    }

    // Закрытие по клику на оверлей
    body.addEventListener('click', function (e) {
        if (e.target === body && body.classList.contains('sidebar-overlay')) {
            sidebar.classList.remove('sidebar-nav--open');
            body.classList.remove('sidebar-overlay');
        }
    });
});
  • Step 5: Подготовить директории для ассетов
cd wp-content/themes/bitwms-child
mkdir -p fonts img/icons js templates template-parts page-templates archive inc

Поместить шрифты Suisse Int'l (woff2) в fonts/. Если шрифты пока недоступны — тема будет использовать Arial как fallback (по брендбуку).

  • Step 6: Активировать дочернюю тему и проверить
wp theme activate bitwms-child

Открыть http://bitwms.local — тема должна активироваться, стили брендбука (цвета, шрифты) должны применяться.

  • Step 7: Коммит
git add themes/bitwms-child/
git commit -m "feat: create child theme with brandbook styles and fonts"

Task 3: Фиксированная боковая панель навигации

Контекст: Ключевой элемент лейаута — фиксированная боковая панель слева (как place.lemma.ru). В свёрнутом виде 70px с иконками, при наведении раскрывается до 250px с подписями. На мобильных — скрывается, появляется гамбургер.

Файлы:

  • Создать: wp-content/themes/bitwms-child/templates/sidebar-nav.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css (добавить стили панели)

  • Модифицировать: wp-content/themes/bitwms-child/functions.php (подключить шаблон)

  • Step 1: Создать SVG-иконки навигации

Создать директорию wp-content/themes/bitwms-child/img/icons/ и поместить туда SVG-файлы. Используем простые моноцветные иконки (чёрный, без теней и градиентов по брендбуку).

Минимальный набор SVG (можно взять из Lucide Icons или Heroicons и упростить до монохромных):

  • warehouse.svg — БИТ.WMS

  • folder.svg — Кейсы

  • document.svg — Статьи

  • camera.svg — Вебинары

  • graduation.svg — Курсы

  • calendar.svg — Мероприятия

  • download.svg — Материалы

  • bell.svg — Новости

  • phone.svg — Контакты

  • telegram.svg — Telegram

  • vk.svg — VK

  • Step 2: Создать шаблон боковой панели

Создать файл wp-content/themes/bitwms-child/templates/sidebar-nav.php:

<?php
/**
 * Фиксированная боковая панель навигации
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

$theme_uri = get_stylesheet_directory_uri();

$nav_items = [
    [
        'label' => 'БИТ.WMS',
        'icon'  => 'warehouse.svg',
        'url'   => '/bit-wms/',
    ],
    [
        'label' => 'Кейсы',
        'icon'  => 'folder.svg',
        'url'   => '/cases/',
    ],
    [
        'label' => 'Статьи',
        'icon'  => 'document.svg',
        'url'   => '/articles/',
    ],
    [
        'label' => 'Вебинары',
        'icon'  => 'camera.svg',
        'url'   => '/webinars/',
    ],
    [
        'label' => 'Курсы',
        'icon'  => 'graduation.svg',
        'url'   => '/courses/',
    ],
    [
        'label' => 'Мероприятия',
        'icon'  => 'calendar.svg',
        'url'   => '/events/',
    ],
    [
        'label' => 'Материалы',
        'icon'  => 'download.svg',
        'url'   => '/materials/',
    ],
    [
        'label' => 'Новости',
        'icon'  => 'bell.svg',
        'url'   => '/news/',
    ],
    [
        'label' => 'Контакты',
        'icon'  => 'phone.svg',
        'url'   => '/contacts/',
    ],
];

$current_path = wp_parse_url(get_permalink(), PHP_URL_PATH);
?>

<aside class="sidebar-nav" role="navigation" aria-label="Основная навигация">
    <div class="sidebar-nav__logo">
        <a href="<?php echo esc_url(home_url('/')); ?>">
            <img src="<?php echo esc_url($theme_uri . '/img/logo-short.svg'); ?>"
                 alt="первыйБит"
                 class="sidebar-nav__logo-img" />
        </a>
    </div>

    <nav class="sidebar-nav__menu">
        <ul class="sidebar-nav__list">
            <?php foreach ($nav_items as $item) :
                $is_active = (strpos($current_path, $item['url']) === 0);
            ?>
            <li class="sidebar-nav__item <?php echo $is_active ? 'sidebar-nav__item--active' : ''; ?>">
                <a href="<?php echo esc_url(home_url($item['url'])); ?>"
                   class="sidebar-nav__link">
                    <span class="sidebar-nav__icon">
                        <img src="<?php echo esc_url($theme_uri . '/img/icons/' . $item['icon']); ?>"
                             alt="" aria-hidden="true" width="24" height="24" />
                    </span>
                    <span class="sidebar-nav__label"><?php echo esc_html($item['label']); ?></span>
                </a>
            </li>
            <?php endforeach; ?>
        </ul>
    </nav>

    <div class="sidebar-nav__social">
        <a href="#" class="sidebar-nav__social-link" aria-label="Telegram">
            <img src="<?php echo esc_url($theme_uri . '/img/icons/telegram.svg'); ?>"
                 alt="" width="20" height="20" />
        </a>
        <a href="#" class="sidebar-nav__social-link" aria-label="VK">
            <img src="<?php echo esc_url($theme_uri . '/img/icons/vk.svg'); ?>"
                 alt="" width="20" height="20" />
        </a>
    </div>
</aside>

<!-- Мобильный гамбургер (виден только на <768px) -->
<button class="hamburger-toggle" aria-label="Открыть меню" aria-expanded="false">
    <span class="hamburger-toggle__bar"></span>
    <span class="hamburger-toggle__bar"></span>
    <span class="hamburger-toggle__bar"></span>
</button>
  • Step 3: Добавить CSS боковой панели

Добавить в конец wp-content/themes/bitwms-child/style.css:

/* ==========================================================================
   Боковая панель навигации
   ========================================================================== */

.sidebar-nav {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--sidebar-width-collapsed);
    height: 100vh;
    background-color: var(--color-white);
    border-right: 1px solid var(--color-gray-light);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    transition: width 0.25s ease;
    overflow: hidden;
}

.sidebar-nav:hover {
    width: var(--sidebar-width-expanded);
}

.sidebar-nav__logo {
    padding: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 60px;
    border-bottom: 1px solid var(--color-gray-light);
}

.sidebar-nav__logo-img {
    width: 36px;
    height: auto;
}

.sidebar-nav__menu {
    flex: 1;
    overflow-y: auto;
    padding: 16px 0;
}

.sidebar-nav__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.sidebar-nav__item {
    margin: 0;
}

.sidebar-nav__link {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 23px;
    color: var(--color-black);
    text-decoration: none;
    font-size: 0.875rem;
    font-weight: 400;
    white-space: nowrap;
    transition: background-color 0.15s;
}

.sidebar-nav__link:hover {
    background-color: var(--color-gray-light);
    text-decoration: none;
    color: var(--color-black);
}

.sidebar-nav__item--active .sidebar-nav__link {
    color: var(--color-primary);
    font-weight: 700;
}

.sidebar-nav__item--active .sidebar-nav__link img {
    filter: brightness(0) saturate(100%) invert(12%) sepia(97%) saturate(5765%) hue-rotate(327deg) brightness(87%) contrast(107%);
}

.sidebar-nav__icon {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.sidebar-nav__label {
    opacity: 0;
    transition: opacity 0.2s ease 0.05s;
}

.sidebar-nav:hover .sidebar-nav__label {
    opacity: 1;
}

.sidebar-nav__social {
    padding: 16px;
    display: flex;
    gap: 12px;
    justify-content: center;
    border-top: 1px solid var(--color-gray-light);
}

.sidebar-nav__social-link {
    opacity: 0.6;
    transition: opacity 0.15s;
}

.sidebar-nav__social-link:hover {
    opacity: 1;
}

/* Сдвиг основного контента */
.site-content,
.site-header,
.site-footer {
    margin-left: var(--sidebar-width-collapsed);
}

/* Гамбургер — скрыт на десктопе */
.hamburger-toggle {
    display: none;
    position: fixed;
    top: 16px;
    left: 16px;
    z-index: 1001;
    background: var(--color-white);
    border: 1px solid var(--color-gray-light);
    padding: 8px;
    cursor: pointer;
    flex-direction: column;
    gap: 4px;
}

.hamburger-toggle__bar {
    display: block;
    width: 24px;
    height: 2px;
    background-color: var(--color-black);
    transition: transform 0.2s;
}

/* ==========================================================================
   Мобильные стили (< 768px)
   ========================================================================== */

@media (max-width: 767px) {
    .sidebar-nav {
        transform: translateX(-100%);
        width: var(--sidebar-width-expanded);
    }

    .sidebar-nav--open {
        transform: translateX(0);
    }

    .sidebar-nav--open .sidebar-nav__label {
        opacity: 1;
    }

    .hamburger-toggle {
        display: flex;
    }

    .site-content,
    .site-header,
    .site-footer {
        margin-left: 0;
    }

    body.sidebar-overlay::after {
        content: '';
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.4);
        z-index: 999;
    }
}
  • Step 4: Подключить боковую панель в тему

Добавить в wp-content/themes/bitwms-child/functions.php (перед закрывающим ?> или в конец):

// Вставка боковой панели после <body>
add_action('generate_before_header', function () {
    get_template_part('templates/sidebar-nav');
});
  • Step 5: Проверить боковую панель

Открыть http://bitwms.local:

  • На десктопе: боковая панель 70px слева с иконками, при наведении раскрывается до 250px с подписями

  • На мобильном (< 768px): панель скрыта, виден гамбургер, по клику панель выезжает с оверлеем

  • Основной контент сдвинут вправо на 70px

  • Step 6: Коммит

git add themes/bitwms-child/
git commit -m "feat: add fixed sidebar navigation with hover expand and mobile hamburger"

Task 4: Верхний хедер

Контекст: Тонкий хедер над основным контентом (правее боковой панели): логотип + слоган слева, телефон + CTA "Заказать демо" + поиск справа. Высота ~60px.

Файлы:

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Модифицировать: wp-content/themes/bitwms-child/functions.php

  • Step 1: Настроить хедер через GeneratePress hooks

Добавить в wp-content/themes/bitwms-child/functions.php:

// Кастомный хедер
add_action('generate_before_header', function () {
    // Боковая панель уже подключена выше
}, 5);

// Переопределяем содержимое хедера
add_filter('generate_header_items_order', function () {
    return ['header-widget', 'site-branding', 'navigation'];
});

Через Customizer GeneratePress (Appearance > Customize > Layout > Header): выбрать лейаут хедера "inline with navigation" или настроить через Elements.

Альтернативно, создать кастомный хедер через GP Elements (Appearance > Elements > Header):

<div class="top-header">
    <div class="top-header__left">
        <a href="/" class="top-header__logo">
            <img src="/wp-content/themes/bitwms-child/img/logo.svg" alt="первыйБит" height="30" />
        </a>
        <span class="top-header__tagline">Экспертный портал по складской логистике</span>
    </div>
    <div class="top-header__right">
        <a href="tel:+73432000000" class="top-header__phone">+7 (343) 200-00-00</a>
        <a href="#demo-form" class="btn btn-primary btn-sm" data-popup="demo">Заказать демо</a>
        <button class="top-header__search" aria-label="Поиск">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
            </svg>
        </button>
    </div>
</div>
  • Step 2: Добавить CSS хедера

Добавить в style.css:

/* ==========================================================================
   Верхний хедер
   ========================================================================== */

.top-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: var(--header-height);
    padding: 0 32px;
    background-color: var(--color-white);
    border-bottom: 1px solid var(--color-gray-light);
}

.top-header__left {
    display: flex;
    align-items: center;
    gap: 16px;
}

.top-header__logo img {
    height: 30px;
    width: auto;
}

.top-header__tagline {
    font-size: 0.875rem;
    color: var(--color-gray-text);
}

.top-header__right {
    display: flex;
    align-items: center;
    gap: 24px;
}

.top-header__phone {
    font-weight: 700;
    color: var(--color-black);
    text-decoration: none;
    font-size: 0.875rem;
}

.top-header__phone:hover {
    color: var(--color-primary);
    text-decoration: none;
}

.btn-sm {
    padding: 8px 20px;
    font-size: 0.875rem;
}

.top-header__search {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-black);
    padding: 4px;
}

.top-header__search:hover {
    color: var(--color-primary);
}

@media (max-width: 767px) {
    .top-header {
        padding: 0 16px 0 56px; /* Отступ под гамбургер */
    }

    .top-header__tagline {
        display: none;
    }

    .top-header__phone {
        display: none;
    }
}
  • Step 3: Проверить хедер

Открыть http://bitwms.local:

  • Хедер 60px, прижат к верху, правее боковой панели

  • Логотип + слоган слева, телефон + "Заказать демо" + лупа справа

  • На мобильном: слоган и телефон скрыты

  • Step 4: Коммит

git add themes/bitwms-child/
git commit -m "feat: add top header with logo, phone and demo CTA"

Task 5: Регистрация кастомных типов записей (CPT)

Контекст: Регистрируем 5 кастомных типов записей: case, webinar, course, event, material. Статьи и Новости — стандартный post с рубриками.

Файлы:

  • Создать: wp-content/themes/bitwms-child/inc/cpt.php

  • Модифицировать: wp-content/themes/bitwms-child/functions.php (подключить файл)

  • Step 1: Создать файл регистрации CPT

Создать файл wp-content/themes/bitwms-child/inc/cpt.php:

<?php
/**
 * Регистрация кастомных типов записей
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

add_action('init', 'bitwms_register_post_types');

function bitwms_register_post_types(): void {
    // Кейсы
    register_post_type('case', [
        'labels' => [
            'name'               => 'Кейсы',
            'singular_name'      => 'Кейс',
            'add_new'            => 'Добавить кейс',
            'add_new_item'       => 'Добавить новый кейс',
            'edit_item'          => 'Редактировать кейс',
            'view_item'          => 'Просмотреть кейс',
            'all_items'          => 'Все кейсы',
            'search_items'       => 'Найти кейс',
            'not_found'          => 'Кейсы не найдены',
            'not_found_in_trash' => 'В корзине кейсов нет',
        ],
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => ['slug' => 'cases'],
        'menu_icon'    => 'dashicons-portfolio',
        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt'],
        'show_in_rest' => true,
    ]);

    // Вебинары
    register_post_type('webinar', [
        'labels' => [
            'name'               => 'Вебинары',
            'singular_name'      => 'Вебинар',
            'add_new'            => 'Добавить вебинар',
            'add_new_item'       => 'Добавить новый вебинар',
            'edit_item'          => 'Редактировать вебинар',
            'view_item'          => 'Просмотреть вебинар',
            'all_items'          => 'Все вебинары',
            'search_items'       => 'Найти вебинар',
            'not_found'          => 'Вебинары не найдены',
            'not_found_in_trash' => 'В корзине вебинаров нет',
        ],
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => ['slug' => 'webinars'],
        'menu_icon'    => 'dashicons-video-alt3',
        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt'],
        'show_in_rest' => true,
    ]);

    // Курсы
    register_post_type('course', [
        'labels' => [
            'name'               => 'Курсы',
            'singular_name'      => 'Курс',
            'add_new'            => 'Добавить курс',
            'add_new_item'       => 'Добавить новый курс',
            'edit_item'          => 'Редактировать курс',
            'view_item'          => 'Просмотреть курс',
            'all_items'          => 'Все курсы',
            'search_items'       => 'Найти курс',
            'not_found'          => 'Курсы не найдены',
            'not_found_in_trash' => 'В корзине курсов нет',
        ],
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => ['slug' => 'courses'],
        'menu_icon'    => 'dashicons-welcome-learn-more',
        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt'],
        'show_in_rest' => true,
    ]);

    // Мероприятия
    register_post_type('event', [
        'labels' => [
            'name'               => 'Мероприятия',
            'singular_name'      => 'Мероприятие',
            'add_new'            => 'Добавить мероприятие',
            'add_new_item'       => 'Добавить новое мероприятие',
            'edit_item'          => 'Редактировать мероприятие',
            'view_item'          => 'Просмотреть мероприятие',
            'all_items'          => 'Все мероприятия',
            'search_items'       => 'Найти мероприятие',
            'not_found'          => 'Мероприятия не найдены',
            'not_found_in_trash' => 'В корзине мероприятий нет',
        ],
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => ['slug' => 'events'],
        'menu_icon'    => 'dashicons-calendar-alt',
        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt'],
        'show_in_rest' => true,
    ]);

    // Материалы
    register_post_type('material', [
        'labels' => [
            'name'               => 'Материалы',
            'singular_name'      => 'Материал',
            'add_new'            => 'Добавить материал',
            'add_new_item'       => 'Добавить новый материал',
            'edit_item'          => 'Редактировать материал',
            'view_item'          => 'Просмотреть материал',
            'all_items'          => 'Все материалы',
            'search_items'       => 'Найти материал',
            'not_found'          => 'Материалы не найдены',
            'not_found_in_trash' => 'В корзине материалов нет',
        ],
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => ['slug' => 'materials'],
        'menu_icon'    => 'dashicons-download',
        'supports'     => ['title', 'thumbnail', 'excerpt'],
        'show_in_rest' => true,
    ]);

    // Таксономии: Отрасли (для кейсов)
    register_taxonomy('industry', ['case'], [
        'labels' => [
            'name'          => 'Отрасли',
            'singular_name' => 'Отрасль',
            'add_new_item'  => 'Добавить отрасль',
        ],
        'public'       => true,
        'hierarchical' => true,
        'rewrite'      => ['slug' => 'industry'],
        'show_in_rest' => true,
    ]);

    // Таксономии: Тип материала
    register_taxonomy('material_type', ['material'], [
        'labels' => [
            'name'          => 'Тип материала',
            'singular_name' => 'Тип материала',
            'add_new_item'  => 'Добавить тип',
        ],
        'public'       => true,
        'hierarchical' => true,
        'rewrite'      => ['slug' => 'material-type'],
        'show_in_rest' => true,
    ]);

    // Рубрики для Статей и Новостей (стандартный post)
    // "Статьи" и "Новости" — рубрики, создаются в админке
}
  • Step 2: Подключить CPT в functions.php

Добавить 'inc/cpt.php' в массив $bitwms_includes в functions.php:

$bitwms_includes = [
    'inc/enqueue.php',
    'inc/cpt.php',
];
  • Step 3: Обновить permalink и проверить
wp rewrite flush

В админке WP: проверить что в меню появились разделы "Кейсы", "Вебинары", "Курсы", "Мероприятия", "Материалы".

Создать рубрики для стандартных постов:

wp term create category "Статьи" --slug=articles
wp term create category "Новости" --slug=news
  • Step 4: Коммит
git add themes/bitwms-child/inc/cpt.php themes/bitwms-child/functions.php
git commit -m "feat: register custom post types (case, webinar, course, event, material)"

Task 6: ACF-поля для кастомных типов записей

Контекст: Настраиваем кастомные поля через ACF Pro для каждого CPT. Поля экспортируем в PHP для версионного контроля.

Файлы:

  • Создать: wp-content/themes/bitwms-child/inc/acf-fields.php

  • Модифицировать: wp-content/themes/bitwms-child/functions.php

  • Step 1: Создать ACF-группы полей в PHP

Создать файл wp-content/themes/bitwms-child/inc/acf-fields.php:

<?php
/**
 * ACF-группы полей для кастомных типов записей
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

if (!function_exists('acf_add_local_field_group')) {
    return;
}

add_action('acf/init', 'bitwms_register_acf_fields');

function bitwms_register_acf_fields(): void {

    // ===== Кейсы =====
    acf_add_local_field_group([
        'key'      => 'group_case_fields',
        'title'    => 'Поля кейса',
        'fields'   => [
            [
                'key'   => 'field_case_client',
                'label' => 'Клиент',
                'name'  => 'case_client',
                'type'  => 'text',
                'required' => 1,
            ],
            [
                'key'   => 'field_case_industry',
                'label' => 'Отрасль',
                'name'  => 'case_industry',
                'type'  => 'text',
            ],
            [
                'key'   => 'field_case_task',
                'label' => 'Задача',
                'name'  => 'case_task',
                'type'  => 'wysiwyg',
                'toolbar' => 'basic',
            ],
            [
                'key'   => 'field_case_solution',
                'label' => 'Решение',
                'name'  => 'case_solution',
                'type'  => 'wysiwyg',
                'toolbar' => 'basic',
            ],
            [
                'key'   => 'field_case_result',
                'label' => 'Результат',
                'name'  => 'case_result',
                'type'  => 'wysiwyg',
                'toolbar' => 'basic',
            ],
            [
                'key'   => 'field_case_quote',
                'label' => 'Цитата клиента',
                'name'  => 'case_quote',
                'type'  => 'textarea',
                'rows'  => 3,
            ],
            [
                'key'   => 'field_case_gallery',
                'label' => 'Галерея',
                'name'  => 'case_gallery',
                'type'  => 'gallery',
                'return_format' => 'array',
            ],
        ],
        'location' => [
            [['param' => 'post_type', 'operator' => '==', 'value' => 'case']],
        ],
    ]);

    // ===== Вебинары =====
    acf_add_local_field_group([
        'key'      => 'group_webinar_fields',
        'title'    => 'Поля вебинара',
        'fields'   => [
            [
                'key'   => 'field_webinar_date',
                'label' => 'Дата проведения',
                'name'  => 'webinar_date',
                'type'  => 'date_time_picker',
                'display_format' => 'd.m.Y H:i',
                'return_format'  => 'Y-m-d H:i:s',
                'required' => 1,
            ],
            [
                'key'   => 'field_webinar_speaker',
                'label' => 'Спикер',
                'name'  => 'webinar_speaker',
                'type'  => 'text',
            ],
            [
                'key'   => 'field_webinar_status',
                'label' => 'Статус',
                'name'  => 'webinar_status',
                'type'  => 'select',
                'choices' => [
                    'upcoming' => 'Анонс',
                    'past'     => 'Прошёл',
                ],
                'default_value' => 'upcoming',
            ],
            [
                'key'   => 'field_webinar_video',
                'label' => 'Запись видео (URL)',
                'name'  => 'webinar_video',
                'type'  => 'url',
                'conditional_logic' => [
                    [['field' => 'field_webinar_status', 'operator' => '==', 'value' => 'past']],
                ],
            ],
            [
                'key'   => 'field_webinar_presentation',
                'label' => 'Презентация (файл)',
                'name'  => 'webinar_presentation',
                'type'  => 'file',
                'return_format' => 'url',
                'conditional_logic' => [
                    [['field' => 'field_webinar_status', 'operator' => '==', 'value' => 'past']],
                ],
            ],
        ],
        'location' => [
            [['param' => 'post_type', 'operator' => '==', 'value' => 'webinar']],
        ],
    ]);

    // ===== Курсы =====
    acf_add_local_field_group([
        'key'      => 'group_course_fields',
        'title'    => 'Поля курса',
        'fields'   => [
            [
                'key'   => 'field_course_program',
                'label' => 'Программа курса',
                'name'  => 'course_program',
                'type'  => 'wysiwyg',
                'toolbar' => 'full',
            ],
            [
                'key'   => 'field_course_duration',
                'label' => 'Длительность',
                'name'  => 'course_duration',
                'type'  => 'text',
                'placeholder' => 'Например: 2 дня (16 часов)',
            ],
            [
                'key'   => 'field_course_format',
                'label' => 'Формат',
                'name'  => 'course_format',
                'type'  => 'select',
                'choices' => [
                    'online'  => 'Онлайн',
                    'offline' => 'Очно',
                    'mixed'   => 'Смешанный',
                ],
            ],
            [
                'key'   => 'field_course_price',
                'label' => 'Стоимость',
                'name'  => 'course_price',
                'type'  => 'text',
                'placeholder' => 'Например: 25 000 руб.',
            ],
        ],
        'location' => [
            [['param' => 'post_type', 'operator' => '==', 'value' => 'course']],
        ],
    ]);

    // ===== Мероприятия =====
    acf_add_local_field_group([
        'key'      => 'group_event_fields',
        'title'    => 'Поля мероприятия',
        'fields'   => [
            [
                'key'   => 'field_event_date',
                'label' => 'Дата проведения',
                'name'  => 'event_date',
                'type'  => 'date_time_picker',
                'display_format' => 'd.m.Y H:i',
                'return_format'  => 'Y-m-d H:i:s',
                'required' => 1,
            ],
            [
                'key'   => 'field_event_location',
                'label' => 'Место проведения',
                'name'  => 'event_location',
                'type'  => 'text',
            ],
            [
                'key'   => 'field_event_format',
                'label' => 'Формат',
                'name'  => 'event_format',
                'type'  => 'select',
                'choices' => [
                    'online'  => 'Онлайн',
                    'offline' => 'Очно',
                    'mixed'   => 'Смешанный',
                ],
            ],
            [
                'key'   => 'field_event_program',
                'label' => 'Программа',
                'name'  => 'event_program',
                'type'  => 'wysiwyg',
                'toolbar' => 'basic',
            ],
            [
                'key'   => 'field_event_registration_url',
                'label' => 'Ссылка на регистрацию',
                'name'  => 'event_registration_url',
                'type'  => 'url',
            ],
        ],
        'location' => [
            [['param' => 'post_type', 'operator' => '==', 'value' => 'event']],
        ],
    ]);

    // ===== Материалы =====
    acf_add_local_field_group([
        'key'      => 'group_material_fields',
        'title'    => 'Поля материала',
        'fields'   => [
            [
                'key'   => 'field_material_file',
                'label' => 'Файл',
                'name'  => 'material_file',
                'type'  => 'file',
                'return_format' => 'array',
            ],
            [
                'key'   => 'field_material_type',
                'label' => 'Тип файла',
                'name'  => 'material_file_type',
                'type'  => 'select',
                'choices' => [
                    'pdf'       => 'PDF',
                    'video'     => 'Видео',
                    'checklist' => 'Чек-лист',
                    'excel'     => 'Excel',
                    'other'     => 'Другое',
                ],
            ],
            [
                'key'   => 'field_material_gated',
                'label' => 'Gated-контент (скачивание за email)',
                'name'  => 'material_gated',
                'type'  => 'true_false',
                'default_value' => 0,
                'ui' => 1,
            ],
        ],
        'location' => [
            [['param' => 'post_type', 'operator' => '==', 'value' => 'material']],
        ],
    ]);
}
  • Step 2: Подключить ACF-поля в functions.php

Добавить 'inc/acf-fields.php' в массив $bitwms_includes:

$bitwms_includes = [
    'inc/enqueue.php',
    'inc/cpt.php',
    'inc/acf-fields.php',
];
  • Step 3: Проверить поля в админке

В админке WP: открыть создание нового Кейса, Вебинара, Курса, Мероприятия, Материала — проверить что все ACF-поля отображаются корректно с нужными типами и условной логикой (например, "Запись видео" появляется только при статусе "Прошёл").

  • Step 4: Коммит
git add themes/bitwms-child/inc/acf-fields.php themes/bitwms-child/functions.php
git commit -m "feat: add ACF field groups for all custom post types"

Task 7: Главная страница — шаблон и герой

Контекст: Шаблон главной страницы: герой + фильтр по рубрикам + лента контента + промо WMS + подписка + клиенты. Начинаем с героя.

Файлы:

  • Создать: wp-content/themes/bitwms-child/page-templates/front-page.php

  • Создать: wp-content/themes/bitwms-child/templates/hero.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Step 1: Создать шаблон главной страницы

Создать файл wp-content/themes/bitwms-child/page-templates/front-page.php:

<?php
/**
 * Template Name: Главная страница
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

get_header();
?>

<main class="front-page">
    <?php get_template_part('templates/hero'); ?>
    <?php get_template_part('templates/section-filter'); ?>
    <?php // Лента контента будет добавлена в Task 9 ?>
    <?php get_template_part('templates/section-promo-wms'); ?>
    <?php get_template_part('templates/section-subscribe'); ?>
    <?php get_template_part('templates/section-clients'); ?>
</main>

<?php
get_footer();
  • Step 2: Создать шаблон героя

Создать файл wp-content/themes/bitwms-child/templates/hero.php:

<?php
/**
 * Герой главной страницы
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;
?>

<section class="hero">
    <div class="container">
        <div class="hero__content">
            <h1 class="hero__title">Всё о складской логистике и&nbsp;автоматизации склада</h1>
            <p class="hero__subtitle">Экспертный портал от Первого Бита&nbsp;&mdash; кейсы, вебинары, курсы и&nbsp;материалы для руководителей складов</p>
            <div class="hero__actions">
                <a href="<?php echo esc_url(home_url('/bit-wms/#demo-form')); ?>" class="btn btn-primary">Заказать демо БИТ.WMS</a>
                <a href="<?php echo esc_url(home_url('/cases/')); ?>" class="btn btn-outline">Смотреть кейсы</a>
            </div>
        </div>
        <div class="hero__stats">
            <div class="hero__stat">
                <span class="hero__stat-number">200+</span>
                <span class="hero__stat-label">проектов внедрения</span>
            </div>
            <div class="hero__stat">
                <span class="hero__stat-number">15+</span>
                <span class="hero__stat-label">лет опыта в&nbsp;WMS</span>
            </div>
            <div class="hero__stat">
                <span class="hero__stat-number">50+</span>
                <span class="hero__stat-label">экспертов в&nbsp;команде</span>
            </div>
        </div>
    </div>
</section>
  • Step 3: Добавить CSS героя

Добавить в style.css:

/* ==========================================================================
   Герой главной страницы
   ========================================================================== */

.hero {
    padding: 80px 0 60px;
}

.hero__title {
    font-size: 3.5rem;
    line-height: 1.1;
    margin: 0 0 24px;
    max-width: 700px;
}

.hero__subtitle {
    font-size: 1.25rem;
    line-height: 1.6;
    color: var(--color-gray-text);
    margin: 0 0 40px;
    max-width: 600px;
}

.hero__actions {
    display: flex;
    gap: 16px;
    margin-bottom: 60px;
}

.hero__stats {
    display: flex;
    gap: 48px;
}

.hero__stat {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.hero__stat-number {
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 2.5rem;
    line-height: 1;
    color: var(--color-primary);
}

.hero__stat-label {
    font-size: 0.875rem;
    color: var(--color-gray-text);
}

@media (max-width: 767px) {
    .hero {
        padding: 40px 0 32px;
    }

    .hero__title {
        font-size: 2rem;
    }

    .hero__subtitle {
        font-size: 1rem;
    }

    .hero__actions {
        flex-direction: column;
        margin-bottom: 40px;
    }

    .hero__stats {
        flex-direction: column;
        gap: 24px;
    }
}
  • Step 4: Назначить шаблон странице "Главная" в админке

В админке WP: Страницы > Главная > в блоке "Атрибуты страницы" выбрать шаблон "Главная страница".

Альтернативно — переименовать файл в front-page.php (без Template Name) и положить в корень дочерней темы, тогда WordPress подхватит его автоматически для статической главной.

  • Step 5: Проверить главную

Открыть http://bitwms.local:

  • Герой с H1, подзаголовком, двумя кнопками, тремя KPI-цифрами

  • Типографика Suisse Int'l / Arial, цвета по брендбуку

  • Адаптивность на мобильном

  • Step 6: Коммит

git add themes/bitwms-child/
git commit -m "feat: add front page template with hero section"

Task 8: Главная — промо-блок WMS, подписка, клиенты

Контекст: Оставшиеся блоки главной страницы: промо БИТ.WMS, подписка на рассылку, логотипы клиентов.

Файлы:

  • Создать: wp-content/themes/bitwms-child/templates/section-promo-wms.php

  • Создать: wp-content/themes/bitwms-child/templates/section-subscribe.php

  • Создать: wp-content/themes/bitwms-child/templates/section-clients.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Step 1: Создать промо-блок БИТ.WMS

Создать файл wp-content/themes/bitwms-child/templates/section-promo-wms.php:

<?php
/**
 * Промо-блок БИТ.WMS на главной
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;
?>

<section class="promo-wms">
    <div class="container">
        <h2 class="promo-wms__title">БИТ.WMS&nbsp;&mdash; комплексное решение для вашего склада</h2>
        <div class="promo-wms__grid">
            <div class="promo-wms__item">
                <span class="promo-wms__icon">&#9889;</span>
                <h3>Быстрое внедрение</h3>
                <p>Знаем бизнес-задачи склада, запускаем проект за&nbsp;недели, а&nbsp;не&nbsp;месяцы</p>
            </div>
            <div class="promo-wms__item">
                <span class="promo-wms__icon">&#9881;</span>
                <h3>Собственная разработка</h3>
                <p>БИТ.WMS&nbsp;&mdash; продукт Первого Бита, гибко адаптируется под ваши процессы</p>
            </div>
            <div class="promo-wms__item">
                <span class="promo-wms__icon">&#10003;</span>
                <h3>Проверено временем</h3>
                <p>200+ проектов внедрения, 15+ лет экспертизы в&nbsp;складской логистике</p>
            </div>
            <div class="promo-wms__item">
                <span class="promo-wms__icon">&#9734;</span>
                <h3>Прозрачные условия</h3>
                <p>Открытая ценовая политика, понятные сроки и&nbsp;этапы</p>
            </div>
        </div>
        <div class="promo-wms__actions">
            <a href="<?php echo esc_url(home_url('/bit-wms/')); ?>" class="btn btn-primary">Подробнее о продукте</a>
            <a href="<?php echo esc_url(home_url('/bit-wms/#demo-form')); ?>" class="btn btn-outline">Заказать демо</a>
        </div>
    </div>
</section>
  • Step 2: Создать блок подписки

Создать файл wp-content/themes/bitwms-child/templates/section-subscribe.php:

<?php
/**
 * Блок подписки на рассылку
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;
?>

<section class="subscribe-section">
    <div class="container">
        <h2 class="subscribe-section__title">Получайте экспертные материалы по&nbsp;складской логистике на&nbsp;почту</h2>
        <form class="subscribe-section__form" action="#" method="post">
            <input type="email"
                   name="email"
                   class="subscribe-section__input"
                   placeholder="Ваш email"
                   required
                   aria-label="Email для подписки" />
            <button type="submit" class="btn btn-primary">Подписаться</button>
        </form>
        <p class="subscribe-section__note">Нажимая кнопку, вы соглашаетесь с&nbsp;<a href="/privacy-policy/">политикой конфиденциальности</a></p>
    </div>
</section>
  • Step 3: Создать блок клиентов

Создать файл wp-content/themes/bitwms-child/templates/section-clients.php:

<?php
/**
 * Блок "Наши клиенты"
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

// Логотипы клиентов можно управлять через ACF Options Page или хардкод
// Для MVP — placeholder-структура
$clients = [
    ['name' => 'Клиент 1', 'logo' => ''],
    ['name' => 'Клиент 2', 'logo' => ''],
    ['name' => 'Клиент 3', 'logo' => ''],
    ['name' => 'Клиент 4', 'logo' => ''],
    ['name' => 'Клиент 5', 'logo' => ''],
    ['name' => 'Клиент 6', 'logo' => ''],
];
?>

<section class="clients-section">
    <div class="container">
        <h2 class="clients-section__title">Нам доверяют</h2>
        <div class="clients-section__grid">
            <?php foreach ($clients as $client) : ?>
            <div class="clients-section__item">
                <?php if ($client['logo']) : ?>
                    <img src="<?php echo esc_url($client['logo']); ?>"
                         alt="<?php echo esc_attr($client['name']); ?>" />
                <?php else : ?>
                    <span class="clients-section__placeholder"><?php echo esc_html($client['name']); ?></span>
                <?php endif; ?>
            </div>
            <?php endforeach; ?>
        </div>
    </div>
</section>
  • Step 4: Добавить CSS для всех трёх блоков

Добавить в style.css:

/* ==========================================================================
   Промо-блок БИТ.WMS
   ========================================================================== */

.promo-wms {
    padding: 80px 0;
    background-color: var(--color-gray-light);
}

.promo-wms__title {
    margin: 0 0 48px;
}

.promo-wms__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 32px;
    margin-bottom: 48px;
}

.promo-wms__item h3 {
    margin: 0 0 8px;
    font-size: 1.25rem;
}

.promo-wms__item p {
    margin: 0;
    color: var(--color-gray-text);
    line-height: 1.6;
}

.promo-wms__icon {
    font-size: 2rem;
    display: block;
    margin-bottom: 12px;
}

.promo-wms__actions {
    display: flex;
    gap: 16px;
}

/* ==========================================================================
   Подписка на рассылку
   ========================================================================== */

.subscribe-section {
    padding: 80px 0;
}

.subscribe-section__title {
    margin: 0 0 32px;
    max-width: 600px;
}

.subscribe-section__form {
    display: flex;
    gap: 12px;
    max-width: 500px;
    margin-bottom: 12px;
}

.subscribe-section__input {
    flex: 1;
    padding: 12px 16px;
    font-size: 1rem;
    font-family: var(--font-body);
    border: 2px solid var(--color-gray-light);
    border-radius: 0;
    background: var(--color-white);
}

.subscribe-section__input:focus {
    outline: none;
    border-color: var(--color-primary);
}

.subscribe-section__note {
    font-size: 0.75rem;
    color: var(--color-gray-text);
}

/* ==========================================================================
   Наши клиенты
   ========================================================================== */

.clients-section {
    padding: 60px 0 80px;
    border-top: 1px solid var(--color-gray-light);
}

.clients-section__title {
    margin: 0 0 32px;
}

.clients-section__grid {
    display: flex;
    flex-wrap: wrap;
    gap: 32px;
    align-items: center;
}

.clients-section__item img {
    max-height: 40px;
    width: auto;
    filter: grayscale(100%);
    opacity: 0.6;
    transition: filter 0.2s, opacity 0.2s;
}

.clients-section__item img:hover {
    filter: grayscale(0%);
    opacity: 1;
}

.clients-section__placeholder {
    display: inline-block;
    padding: 12px 24px;
    background: var(--color-gray-light);
    font-size: 0.875rem;
    color: var(--color-gray-text);
}

@media (max-width: 767px) {
    .promo-wms__grid {
        grid-template-columns: 1fr;
    }

    .promo-wms__actions {
        flex-direction: column;
    }

    .subscribe-section__form {
        flex-direction: column;
    }
}
  • Step 5: Проверить все блоки на главной

Открыть http://bitwms.local:

  • Промо-блок WMS с 4 преимуществами на сером фоне

  • Блок подписки с полем email

  • Блок клиентов с placeholder-ами

  • Step 6: Коммит

git add themes/bitwms-child/
git commit -m "feat: add promo WMS, subscribe, and clients sections to front page"

Task 9: Лента контента с AJAX-фильтрацией на главной

Контекст: Горизонтальная полоса тегов-фильтров + карточная сетка контента + "Показать ещё". Фильтрация через AJAX без перезагрузки.

Файлы:

  • Создать: wp-content/themes/bitwms-child/templates/section-filter.php

  • Создать: wp-content/themes/bitwms-child/templates/content-card.php

  • Создать: wp-content/themes/bitwms-child/inc/ajax-filter.php

  • Создать: wp-content/themes/bitwms-child/js/ajax-filter.js

  • Модифицировать: wp-content/themes/bitwms-child/functions.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Модифицировать: wp-content/themes/bitwms-child/inc/enqueue.php

  • Step 1: Создать шаблон фильтра

Создать файл wp-content/themes/bitwms-child/templates/section-filter.php:

<?php
/**
 * Блок фильтрации по типам контента
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

$filters = [
    ['slug' => 'all',       'label' => 'Все'],
    ['slug' => 'post',      'label' => 'Статьи'],
    ['slug' => 'case',      'label' => 'Кейсы'],
    ['slug' => 'webinar',   'label' => 'Вебинары'],
    ['slug' => 'course',    'label' => 'Курсы'],
    ['slug' => 'event',     'label' => 'Мероприятия'],
    ['slug' => 'material',  'label' => 'Материалы'],
];
?>

<section class="content-feed">
    <div class="container">
        <div class="filter-bar" role="tablist">
            <?php foreach ($filters as $filter) : ?>
            <button class="filter-bar__btn <?php echo $filter['slug'] === 'all' ? 'filter-bar__btn--active' : ''; ?>"
                    data-filter="<?php echo esc_attr($filter['slug']); ?>"
                    role="tab"
                    aria-selected="<?php echo $filter['slug'] === 'all' ? 'true' : 'false'; ?>">
                <?php echo esc_html($filter['label']); ?>
            </button>
            <?php endforeach; ?>
        </div>

        <div class="content-grid" id="content-grid">
            <?php
            // Начальная загрузка — последние 6 записей из всех CPT
            $initial_query = new WP_Query([
                'post_type'      => ['post', 'case', 'webinar', 'course', 'event', 'material'],
                'posts_per_page' => 6,
                'orderby'        => 'date',
                'order'          => 'DESC',
            ]);

            if ($initial_query->have_posts()) :
                while ($initial_query->have_posts()) :
                    $initial_query->the_post();
                    get_template_part('templates/content-card');
                endwhile;
                wp_reset_postdata();
            endif;
            ?>
        </div>

        <?php if ($initial_query->found_posts > 6) : ?>
        <div class="content-feed__more">
            <button class="btn btn-outline" id="load-more-btn" data-page="1">Показать ещё</button>
        </div>
        <?php endif; ?>
    </div>
</section>
  • Step 2: Создать универсальную карточку контента

Создать файл wp-content/themes/bitwms-child/templates/content-card.php:

<?php
/**
 * Универсальная карточка контента
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

$post_type = get_post_type();
$type_labels = [
    'post'     => 'Статья',
    'case'     => 'Кейс',
    'webinar'  => 'Вебинар',
    'course'   => 'Курс',
    'event'    => 'Мероприятие',
    'material' => 'Материал',
];
$type_label = $type_labels[$post_type] ?? 'Запись';

// Для постов с рубрикой "Новости" — переопределяем метку
if ($post_type === 'post') {
    $categories = get_the_category();
    foreach ($categories as $cat) {
        if ($cat->slug === 'news') {
            $type_label = 'Новость';
            break;
        }
    }
}
?>

<article class="content-card">
    <a href="<?php the_permalink(); ?>" class="content-card__link">
        <?php if (has_post_thumbnail()) : ?>
        <div class="content-card__image">
            <?php the_post_thumbnail('medium_large'); ?>
        </div>
        <?php else : ?>
        <div class="content-card__image content-card__image--placeholder"></div>
        <?php endif; ?>

        <div class="content-card__body">
            <span class="badge"><?php echo esc_html($type_label); ?></span>
            <h3 class="content-card__title"><?php the_title(); ?></h3>
            <?php if (has_excerpt()) : ?>
            <p class="content-card__excerpt"><?php echo esc_html(wp_trim_words(get_the_excerpt(), 15)); ?></p>
            <?php endif; ?>
            <div class="content-card__meta">
                <time datetime="<?php echo esc_attr(get_the_date('Y-m-d')); ?>">
                    <?php echo esc_html(get_the_date('d.m.Y')); ?>
                </time>
            </div>
        </div>
    </a>
</article>
  • Step 3: Создать AJAX-обработчик

Создать файл wp-content/themes/bitwms-child/inc/ajax-filter.php:

<?php
/**
 * AJAX-фильтрация ленты контента на главной
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

add_action('wp_ajax_bitwms_filter', 'bitwms_ajax_filter');
add_action('wp_ajax_nopriv_bitwms_filter', 'bitwms_ajax_filter');

function bitwms_ajax_filter(): void {
    $post_type = sanitize_text_field($_POST['post_type'] ?? 'all');
    $page      = absint($_POST['page'] ?? 1);
    $per_page  = 6;

    $args = [
        'posts_per_page' => $per_page,
        'paged'          => $page,
        'orderby'        => 'date',
        'order'          => 'DESC',
    ];

    if ($post_type === 'all') {
        $args['post_type'] = ['post', 'case', 'webinar', 'course', 'event', 'material'];
    } else {
        $args['post_type'] = $post_type;
    }

    $query = new WP_Query($args);

    ob_start();
    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            get_template_part('templates/content-card');
        }
        wp_reset_postdata();
    }
    $html = ob_get_clean();

    wp_send_json_success([
        'html'     => $html,
        'has_more' => $page < $query->max_num_pages,
    ]);
}
  • Step 4: Создать JS для AJAX-фильтрации

Создать файл wp-content/themes/bitwms-child/js/ajax-filter.js:

/**
 * AJAX-фильтрация ленты контента + "Показать ещё"
 */
document.addEventListener('DOMContentLoaded', function () {
    const filterBar = document.querySelector('.filter-bar');
    const contentGrid = document.getElementById('content-grid');
    const loadMoreBtn = document.getElementById('load-more-btn');

    if (!filterBar || !contentGrid) return;

    let currentFilter = 'all';
    let currentPage = 1;

    // Фильтрация по типу
    filterBar.addEventListener('click', function (e) {
        const btn = e.target.closest('.filter-bar__btn');
        if (!btn) return;

        // Обновляем активную кнопку
        filterBar.querySelectorAll('.filter-bar__btn').forEach(function (b) {
            b.classList.remove('filter-bar__btn--active');
            b.setAttribute('aria-selected', 'false');
        });
        btn.classList.add('filter-bar__btn--active');
        btn.setAttribute('aria-selected', 'true');

        currentFilter = btn.dataset.filter;
        currentPage = 1;
        loadContent(false);
    });

    // "Показать ещё"
    if (loadMoreBtn) {
        loadMoreBtn.addEventListener('click', function () {
            currentPage++;
            loadContent(true);
        });
    }

    function loadContent(append) {
        var formData = new FormData();
        formData.append('action', 'bitwms_filter');
        formData.append('post_type', currentFilter);
        formData.append('page', currentPage);

        fetch(bitwmsAjax.url, {
            method: 'POST',
            body: formData,
        })
        .then(function (response) { return response.json(); })
        .then(function (data) {
            if (data.success) {
                if (append) {
                    contentGrid.insertAdjacentHTML('beforeend', data.data.html);
                } else {
                    contentGrid.innerHTML = data.data.html;
                }

                if (loadMoreBtn) {
                    loadMoreBtn.style.display = data.data.has_more ? '' : 'none';
                }
            }
        });
    }
});
  • Step 5: Подключить AJAX-обработчик и скрипт

Добавить 'inc/ajax-filter.php' в $bitwms_includes в functions.php:

$bitwms_includes = [
    'inc/enqueue.php',
    'inc/cpt.php',
    'inc/acf-fields.php',
    'inc/ajax-filter.php',
];

Обновить inc/enqueue.php — добавить скрипт и локализацию:

<?php
/**
 * Подключение скриптов и стилей
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

add_action('wp_enqueue_scripts', function () {
    $theme_version = wp_get_theme()->get('Version');
    $theme_uri = get_stylesheet_directory_uri();

    // Боковая навигация
    wp_enqueue_script(
        'bitwms-sidebar-nav',
        $theme_uri . '/js/sidebar-nav.js',
        [],
        $theme_version,
        true
    );

    // AJAX-фильтрация (только на главной)
    if (is_front_page()) {
        wp_enqueue_script(
            'bitwms-ajax-filter',
            $theme_uri . '/js/ajax-filter.js',
            [],
            $theme_version,
            true
        );
        wp_localize_script('bitwms-ajax-filter', 'bitwmsAjax', [
            'url' => admin_url('admin-ajax.php'),
        ]);
    }
}, 20);
  • Step 6: Добавить CSS для фильтра и сетки карточек

Добавить в style.css:

/* ==========================================================================
   Фильтр-бар
   ========================================================================== */

.filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 32px;
    padding-bottom: 24px;
    border-bottom: 1px solid var(--color-gray-light);
}

.filter-bar__btn {
    padding: 8px 20px;
    font-family: var(--font-body);
    font-size: 0.875rem;
    font-weight: 400;
    background: none;
    border: 1px solid var(--color-gray-light);
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
    color: var(--color-black);
}

.filter-bar__btn:hover {
    border-color: var(--color-black);
}

.filter-bar__btn--active {
    background-color: var(--color-black);
    color: var(--color-white);
    border-color: var(--color-black);
    font-weight: 700;
}

/* ==========================================================================
   Сетка карточек контента
   ========================================================================== */

.content-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    margin-bottom: 32px;
}

.content-card__link {
    display: block;
    text-decoration: none;
    color: inherit;
    transition: opacity 0.15s;
}

.content-card__link:hover {
    text-decoration: none;
    color: inherit;
}

.content-card__link:hover .content-card__title {
    color: var(--color-primary);
}

.content-card__image {
    aspect-ratio: 16 / 10;
    overflow: hidden;
    margin-bottom: 16px;
    background-color: var(--color-gray-light);
}

.content-card__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.content-card__body .badge {
    margin-bottom: 8px;
}

.content-card__title {
    font-size: 1.125rem;
    margin: 0 0 8px;
    line-height: 1.3;
    transition: color 0.15s;
}

.content-card__excerpt {
    font-size: 0.875rem;
    color: var(--color-gray-text);
    margin: 0 0 12px;
    line-height: 1.5;
}

.content-card__meta {
    font-size: 0.75rem;
    color: var(--color-gray-text);
}

.content-feed__more {
    text-align: center;
    margin-bottom: 60px;
}

@media (max-width: 1024px) {
    .content-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 767px) {
    .content-grid {
        grid-template-columns: 1fr;
    }
}
  • Step 7: Проверить фильтрацию

Создать несколько тестовых записей разных типов в админке. Открыть главную:

  • Фильтр-бар с кнопками типов контента

  • Клик по типу фильтрует карточки без перезагрузки

  • "Показать ещё" подгружает следующую порцию

  • Карточки в сетке 3 колонки (2 на планшете, 1 на мобильном)

  • Step 8: Коммит

git add themes/bitwms-child/
git commit -m "feat: add content feed with AJAX filtering and load more on front page"

Task 10: Страница продукта БИТ.WMS

Контекст: Продуктовая страница: герой, функции, "Почему Первый Бит", кейсы, другие решения, форма демо, анкета.

Файлы:

  • Создать: wp-content/themes/bitwms-child/page-templates/page-bit-wms.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Step 1: Создать шаблон страницы БИТ.WMS

Создать файл wp-content/themes/bitwms-child/page-templates/page-bit-wms.php:

<?php
/**
 * Template Name: БИТ.WMS
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

get_header();
?>

<main class="page-bitwms">

    <!-- Герой -->
    <section class="bitwms-hero">
        <div class="container">
            <h1>БИТ.WMS</h1>
            <p class="bitwms-hero__subtitle">Комплексное решение для управления складом</p>
            <p class="bitwms-hero__desc">БИТ.WMS — это полнофункциональная система управления складом от компании «Первый Бит». Автоматизирует все складские процессы: от приёмки до отгрузки, с полным контролем на каждом этапе.</p>
            <div class="bitwms-hero__actions">
                <a href="#demo-form" class="btn btn-primary">Заказать демо</a>
                <a href="#" class="btn btn-outline" data-popup="download-presentation">Скачать презентацию</a>
            </div>
        </div>
    </section>

    <!-- Функции -->
    <section class="bitwms-features">
        <div class="container">
            <h2>Функции БИТ.WMS</h2>
            <div class="features-grid">
                <?php
                $features = [
                    ['title' => 'Приёмка', 'desc' => 'Контроль поступающего товара, сверка с заказами, маркировка', 'result' => 'Сокращение времени приёмки на 40%'],
                    ['title' => 'Размещение', 'desc' => 'Автоматический подбор ячеек хранения по заданным правилам', 'result' => 'Оптимизация использования площади склада'],
                    ['title' => 'Хранение', 'desc' => 'Адресное хранение, контроль сроков годности, серийных номеров', 'result' => 'Снижение потерь от просрочки'],
                    ['title' => 'Отбор', 'desc' => 'Волновой и кластерный отбор, оптимизация маршрутов сборки', 'result' => 'Увеличение скорости сборки заказов на 30%'],
                    ['title' => 'Отгрузка', 'desc' => 'Контроль отгрузки, формирование документов, сверка с заказом', 'result' => 'Снижение ошибок отгрузки до 0,1%'],
                    ['title' => 'Инвентаризация', 'desc' => 'Плановая и выборочная инвентаризация с ТСД', 'result' => 'Инвентаризация за часы вместо дней'],
                ];
                foreach ($features as $f) : ?>
                <div class="feature-card">
                    <h3 class="feature-card__title"><?php echo esc_html($f['title']); ?></h3>
                    <p class="feature-card__desc"><?php echo esc_html($f['desc']); ?></p>
                    <p class="feature-card__result"><strong>Результат:</strong> <?php echo esc_html($f['result']); ?></p>
                </div>
                <?php endforeach; ?>
            </div>
        </div>
    </section>

    <!-- Почему Первый Бит -->
    <section class="bitwms-why">
        <div class="container">
            <h2>Почему Первый Бит</h2>
            <div class="why-grid">
                <div class="why-item">
                    <h3 class="why-item__title">Быстро</h3>
                    <p>Мы — профессионалы, знаем бизнес-задачи склада и процессы. Запускаем проекты за недели.</p>
                </div>
                <div class="why-item">
                    <h3 class="why-item__title">Просто</h3>
                    <p>Знаем все о WMS-решениях и имеем собственный программный продукт БИТ.WMS.</p>
                </div>
                <div class="why-item">
                    <h3 class="why-item__title">Качественно</h3>
                    <p>Первый Бит — это результат. 200+ успешных проектов, многолетний опыт.</p>
                </div>
                <div class="why-item">
                    <h3 class="why-item__title">Открыто</h3>
                    <p>Прозрачная ценовая политика. Понятные сроки и этапы внедрения.</p>
                </div>
            </div>
        </div>
    </section>

    <!-- Кейсы -->
    <section class="bitwms-cases">
        <div class="container">
            <h2>Кейсы внедрения</h2>
            <div class="content-grid">
                <?php
                $cases_query = new WP_Query([
                    'post_type'      => 'case',
                    'posts_per_page' => 3,
                    'orderby'        => 'date',
                    'order'          => 'DESC',
                ]);
                if ($cases_query->have_posts()) :
                    while ($cases_query->have_posts()) :
                        $cases_query->the_post();
                        get_template_part('templates/content-card');
                    endwhile;
                    wp_reset_postdata();
                else : ?>
                    <p>Кейсы скоро появятся.</p>
                <?php endif; ?>
            </div>
            <p><a href="<?php echo esc_url(home_url('/cases/')); ?>" class="btn btn-outline">Все кейсы</a></p>
        </div>
    </section>

    <!-- Другие решения -->
    <section class="bitwms-other">
        <div class="container">
            <h2>Возможно, вам будет интересно</h2>
            <div class="other-grid">
                <div class="other-card">
                    <h3>1C:WMS Логистика</h3>
                    <p>Управление складом на платформе 1С</p>
                </div>
                <div class="other-card">
                    <h3>Клеверенс</h3>
                    <p>Мобильная автоматизация склада</p>
                </div>
                <div class="other-card">
                    <h3>1C:TMS</h3>
                    <p>Управление транспортной логистикой</p>
                </div>
            </div>
        </div>
    </section>

    <!-- Форма "Заказать демо" -->
    <section class="bitwms-demo" id="demo-form">
        <div class="container">
            <h2>Заказать демо БИТ.WMS</h2>
            <p>Оставьте заявку, и наш эксперт свяжется с вами для демонстрации системы</p>
            <?php
            // Contact Form 7 shortcode — ID формы подставить после создания
            // echo do_shortcode('[contact-form-7 id="XXX" title="Заказать демо"]');
            ?>
            <form class="demo-form" action="#" method="post">
                <div class="demo-form__grid">
                    <input type="text" name="name" placeholder="Имя *" required />
                    <input type="text" name="company" placeholder="Компания" />
                    <input type="tel" name="phone" placeholder="Телефон *" required />
                    <input type="email" name="email" placeholder="Email *" required />
                </div>
                <textarea name="comment" placeholder="Комментарий" rows="3"></textarea>
                <label class="demo-form__consent">
                    <input type="checkbox" required />
                    Согласен на <a href="/privacy-policy/" target="_blank">обработку персональных данных</a>
                </label>
                <button type="submit" class="btn btn-primary">Отправить заявку</button>
            </form>
            <p class="demo-form__anketa">
                Нужен детальный расчёт? <a href="<?php echo esc_url(home_url('/bit-wms/anketa/')); ?>">Заполните анкету</a>
            </p>
        </div>
    </section>

</main>

<?php
get_footer();
  • Step 2: Добавить CSS для страницы БИТ.WMS

Добавить в style.css:

/* ==========================================================================
   Страница БИТ.WMS
   ========================================================================== */

.bitwms-hero {
    padding: 80px 0 60px;
}

.bitwms-hero h1 {
    font-size: 4rem;
    margin: 0 0 16px;
}

.bitwms-hero__subtitle {
    font-size: 1.5rem;
    color: var(--color-gray-text);
    margin: 0 0 24px;
}

.bitwms-hero__desc {
    font-size: 1.125rem;
    line-height: 1.6;
    max-width: 700px;
    margin: 0 0 32px;
}

.bitwms-hero__actions {
    display: flex;
    gap: 16px;
}

/* Функции */
.bitwms-features {
    padding: 80px 0;
    background-color: var(--color-gray-light);
}

.features-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    margin-top: 32px;
}

.feature-card {
    background: var(--color-white);
    padding: 32px;
}

.feature-card__title {
    margin: 0 0 12px;
}

.feature-card__desc {
    color: var(--color-gray-text);
    line-height: 1.6;
    margin: 0 0 16px;
}

.feature-card__result {
    font-size: 0.875rem;
    color: var(--color-primary);
    margin: 0;
}

/* Почему Первый Бит */
.bitwms-why {
    padding: 80px 0;
}

.why-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 32px;
    margin-top: 32px;
}

.why-item__title {
    font-size: 1.5rem;
    margin: 0 0 12px;
}

.why-item p {
    color: var(--color-gray-text);
    line-height: 1.6;
    margin: 0;
}

/* Кейсы */
.bitwms-cases {
    padding: 60px 0;
    border-top: 1px solid var(--color-gray-light);
}

/* Другие решения */
.bitwms-other {
    padding: 60px 0;
    background-color: var(--color-gray-light);
}

.other-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    margin-top: 32px;
}

.other-card {
    background: var(--color-white);
    padding: 32px;
}

.other-card h3 {
    margin: 0 0 8px;
}

.other-card p {
    color: var(--color-gray-text);
    margin: 0;
}

/* Форма демо */
.bitwms-demo {
    padding: 80px 0;
}

.demo-form {
    max-width: 600px;
    margin-top: 24px;
}

.demo-form__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin-bottom: 12px;
}

.demo-form input[type="text"],
.demo-form input[type="tel"],
.demo-form input[type="email"],
.demo-form textarea {
    width: 100%;
    padding: 12px 16px;
    font-family: var(--font-body);
    font-size: 1rem;
    border: 2px solid var(--color-gray-light);
    border-radius: 0;
    background: var(--color-white);
    box-sizing: border-box;
}

.demo-form input:focus,
.demo-form textarea:focus {
    outline: none;
    border-color: var(--color-primary);
}

.demo-form textarea {
    margin-bottom: 16px;
}

.demo-form__consent {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 0.875rem;
    margin-bottom: 24px;
    color: var(--color-gray-text);
}

.demo-form__anketa {
    margin-top: 24px;
    font-size: 0.875rem;
    color: var(--color-gray-text);
}

@media (max-width: 767px) {
    .bitwms-hero h1 {
        font-size: 2.5rem;
    }

    .bitwms-hero__actions {
        flex-direction: column;
    }

    .features-grid,
    .other-grid {
        grid-template-columns: 1fr;
    }

    .why-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .demo-form__grid {
        grid-template-columns: 1fr;
    }
}
  • Step 3: Создать страницу в WP и назначить шаблон

В админке WP: создать страницу "БИТ.WMS" со slug bit-wms, назначить шаблон "БИТ.WMS".

  • Step 4: Проверить страницу

Открыть http://bitwms.local/bit-wms/:

  • Все секции отображаются

  • Форма демо работает визуально

  • Адаптивность на мобильном

  • Step 5: Коммит

git add themes/bitwms-child/
git commit -m "feat: add BIT.WMS product page template with features, benefits, and demo form"

Task 11: Архивные шаблоны и детальные страницы CPT

Контекст: Единый шаблон архива для всех CPT + детальные шаблоны для кейсов, вебинаров, курсов, мероприятий.

Файлы:

  • Создать: wp-content/themes/bitwms-child/archive/archive-cpt.php

  • Создать: wp-content/themes/bitwms-child/template-parts/single-case.php

  • Создать: wp-content/themes/bitwms-child/template-parts/single-webinar.php

  • Создать: wp-content/themes/bitwms-child/template-parts/single-course.php

  • Создать: wp-content/themes/bitwms-child/template-parts/single-event.php

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Step 1: Создать архивные шаблоны

WordPress ищет шаблоны по иерархии: archive-{post_type}.php. Создаём по одному для каждого CPT (все используют единый layout).

Создать файл wp-content/themes/bitwms-child/archive-case.php:

<?php
/**
 * Архив Кейсов
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

get_header();
?>

<main class="archive-page">
    <div class="container">
        <h1 class="archive-page__title">Кейсы</h1>

        <div class="content-grid">
            <?php
            if (have_posts()) :
                while (have_posts()) :
                    the_post();
                    get_template_part('templates/content-card');
                endwhile;
            else : ?>
                <p>Кейсы скоро появятся.</p>
            <?php endif; ?>
        </div>

        <?php the_posts_pagination([
            'prev_text' => '&larr;',
            'next_text' => '&rarr;',
        ]); ?>
    </div>
</main>

<?php
get_footer();

Создать аналогичные файлы для остальных CPT — archive-webinar.php, archive-course.php, archive-event.php, archive-material.php — меняя только заголовок H1 ("Вебинары", "Курсы", "Мероприятия", "Материалы") и текст "не найдено".

  • Step 2: Создать детальный шаблон кейса

Создать файл wp-content/themes/bitwms-child/single-case.php:

<?php
/**
 * Детальная страница кейса
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

get_header();
the_post();

$client   = get_field('case_client');
$industry = get_field('case_industry');
$task     = get_field('case_task');
$solution = get_field('case_solution');
$result   = get_field('case_result');
$quote    = get_field('case_quote');
$gallery  = get_field('case_gallery');
?>

<main class="single-case">
    <div class="container">
        <article>
            <h1><?php the_title(); ?></h1>

            <div class="single-case__meta">
                <?php if ($client) : ?>
                    <div class="single-case__meta-item">
                        <strong>Клиент:</strong> <?php echo esc_html($client); ?>
                    </div>
                <?php endif; ?>
                <?php if ($industry) : ?>
                    <div class="single-case__meta-item">
                        <strong>Отрасль:</strong> <?php echo esc_html($industry); ?>
                    </div>
                <?php endif; ?>
            </div>

            <?php if ($task) : ?>
            <section class="single-case__section">
                <h2>Задача</h2>
                <?php echo wp_kses_post($task); ?>
            </section>
            <?php endif; ?>

            <?php if ($solution) : ?>
            <section class="single-case__section">
                <h2>Решение</h2>
                <?php echo wp_kses_post($solution); ?>
            </section>
            <?php endif; ?>

            <?php if ($result) : ?>
            <section class="single-case__section">
                <h2>Результат</h2>
                <?php echo wp_kses_post($result); ?>
            </section>
            <?php endif; ?>

            <?php if ($gallery) : ?>
            <section class="single-case__gallery">
                <h2>Галерея</h2>
                <div class="gallery-grid">
                    <?php foreach ($gallery as $img) : ?>
                    <a href="<?php echo esc_url($img['url']); ?>" target="_blank">
                        <img src="<?php echo esc_url($img['sizes']['medium_large']); ?>"
                             alt="<?php echo esc_attr($img['alt']); ?>" />
                    </a>
                    <?php endforeach; ?>
                </div>
            </section>
            <?php endif; ?>

            <?php if ($quote) : ?>
            <blockquote class="single-case__quote">
                <p><?php echo esc_html($quote); ?></p>
            </blockquote>
            <?php endif; ?>

            <div class="single-case__cta">
                <p>Хотите такой же результат?</p>
                <a href="<?php echo esc_url(home_url('/bit-wms/#demo-form')); ?>" class="btn btn-primary">Закажите консультацию</a>
            </div>
        </article>

        <!-- Похожие кейсы -->
        <section class="related-posts">
            <h2>Другие кейсы</h2>
            <div class="content-grid">
                <?php
                $related = new WP_Query([
                    'post_type'      => 'case',
                    'posts_per_page' => 3,
                    'post__not_in'   => [get_the_ID()],
                    'orderby'        => 'rand',
                ]);
                if ($related->have_posts()) :
                    while ($related->have_posts()) :
                        $related->the_post();
                        get_template_part('templates/content-card');
                    endwhile;
                    wp_reset_postdata();
                endif;
                ?>
            </div>
        </section>
    </div>
</main>

<?php
get_footer();
  • Step 3: Создать детальные шаблоны вебинара, курса, мероприятия

Создать single-webinar.php, single-course.php, single-event.php по аналогичной структуре, используя соответствующие ACF-поля из Task 6. Каждый шаблон содержит:

  • Заголовок H1

  • ACF-поля в нужном порядке

  • CTA-блок внизу (регистрация / запись)

  • Блок "Похожие" (3 карточки того же типа)

  • Step 4: Добавить CSS для детальных страниц

Добавить в style.css:

/* ==========================================================================
   Архивные страницы
   ========================================================================== */

.archive-page {
    padding: 60px 0;
}

.archive-page__title {
    margin: 0 0 32px;
}

/* ==========================================================================
   Детальные страницы
   ========================================================================== */

.single-case,
.single-webinar,
.single-course,
.single-event {
    padding: 60px 0;
}

.single-case__meta {
    display: flex;
    gap: 24px;
    margin-bottom: 40px;
    padding-bottom: 24px;
    border-bottom: 1px solid var(--color-gray-light);
}

.single-case__meta-item {
    font-size: 0.875rem;
    color: var(--color-gray-text);
}

.single-case__section {
    margin-bottom: 40px;
}

.single-case__section h2 {
    font-size: 1.5rem;
    margin: 0 0 16px;
}

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    margin-top: 16px;
}

.gallery-grid img {
    width: 100%;
    height: auto;
}

.single-case__quote {
    border-left: 4px solid var(--color-primary);
    padding: 24px 32px;
    margin: 40px 0;
    background-color: var(--color-gray-light);
    font-style: italic;
    font-size: 1.125rem;
    line-height: 1.6;
}

.single-case__cta {
    padding: 40px 0;
    border-top: 1px solid var(--color-gray-light);
}

.single-case__cta p {
    font-size: 1.25rem;
    font-weight: 700;
    margin: 0 0 16px;
}

.related-posts {
    padding: 60px 0 0;
    border-top: 1px solid var(--color-gray-light);
}

.related-posts h2 {
    margin: 0 0 24px;
}

/* Пагинация */
.nav-links {
    display: flex;
    gap: 8px;
    justify-content: center;
    margin-top: 32px;
}

.nav-links .page-numbers {
    padding: 8px 16px;
    border: 1px solid var(--color-gray-light);
    color: var(--color-black);
    text-decoration: none;
}

.nav-links .page-numbers.current {
    background: var(--color-black);
    color: var(--color-white);
    border-color: var(--color-black);
}

@media (max-width: 767px) {
    .single-case__meta {
        flex-direction: column;
        gap: 8px;
    }

    .gallery-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}
  • Step 5: Проверить архивы и детальные страницы

Создать тестовые записи каждого типа. Проверить:

  • /cases/ — архив кейсов с карточками

  • /cases/test-case/ — детальная страница с ACF-полями

  • Аналогично для вебинаров, курсов, мероприятий, материалов

  • Step 6: Коммит

git add themes/bitwms-child/
git commit -m "feat: add archive and single templates for all custom post types"

Task 12: Страница контактов и футер

Контекст: Страница контактов с формой обратной связи. Кастомный футер с колонками.

Файлы:

  • Создать: wp-content/themes/bitwms-child/page-templates/page-contacts.php

  • Модифицировать: wp-content/themes/bitwms-child/functions.php (футер)

  • Модифицировать: wp-content/themes/bitwms-child/style.css

  • Step 1: Создать шаблон страницы контактов

Создать файл wp-content/themes/bitwms-child/page-templates/page-contacts.php:

<?php
/**
 * Template Name: Контакты
 *
 * @package bitwms
 */

defined('ABSPATH') || exit;

get_header();
?>

<main class="page-contacts">
    <div class="container">
        <h1>Контакты</h1>

        <div class="contacts-grid">
            <div class="contacts-info">
                <h2>Екатеринбург Проектный центр</h2>
                <p><strong>Телефон:</strong> <a href="tel:+73432000000">+7 (343) 200-00-00</a></p>
                <p><strong>Email:</strong> <a href="mailto:wms@1bit.ru">wms@1bit.ru</a></p>
                <p><strong>Адрес:</strong> г.&nbsp;Екатеринбург</p>
            </div>

            <div class="contacts-form">
                <h2>Напишите нам</h2>
                <?php // echo do_shortcode('[contact-form-7 id="XXX" title="Обратная связь"]'); ?>
                <form action="#" method="post">
                    <input type="text" name="name" placeholder="Имя *" required />
                    <input type="email" name="email" placeholder="Email *" required />
                    <textarea name="message" placeholder="Сообщение" rows="5"></textarea>
                    <label class="demo-form__consent">
                        <input type="checkbox" required />
                        Согласен на <a href="/privacy-policy/" target="_blank">обработку персональных данных</a>
                    </label>
                    <button type="submit" class="btn btn-primary">Отправить</button>
                </form>
            </div>
        </div>
    </div>
</main>

<?php
get_footer();
  • Step 2: Настроить кастомный футер

Добавить в functions.php:

// Кастомный футер
add_action('generate_before_footer_content', function () {
    ?>
    <div class="custom-footer">
        <div class="container">
            <div class="custom-footer__grid">
                <div class="custom-footer__col">
                    <img src="<?php echo esc_url(get_stylesheet_directory_uri() . '/img/logo.svg'); ?>"
                         alt="первыйБит" height="24" />
                    <p>Екатеринбург Проектный центр</p>
                    <p><a href="tel:+73432000000">+7 (343) 200-00-00</a></p>
                    <p><a href="mailto:wms@1bit.ru">wms@1bit.ru</a></p>
                </div>
                <div class="custom-footer__col">
                    <h4>Разделы</h4>
                    <ul>
                        <li><a href="/cases/">Кейсы</a></li>
                        <li><a href="/articles/">Статьи</a></li>
                        <li><a href="/webinars/">Вебинары</a></li>
                        <li><a href="/courses/">Курсы</a></li>
                        <li><a href="/events/">Мероприятия</a></li>
                        <li><a href="/materials/">Материалы</a></li>
                    </ul>
                </div>
                <div class="custom-footer__col">
                    <h4>Продукты</h4>
                    <ul>
                        <li><a href="/bit-wms/">БИТ.WMS</a></li>
                        <li>1C:WMS</li>
                        <li>Клеверенс</li>
                        <li>1C:TMS</li>
                    </ul>
                </div>
                <div class="custom-footer__col">
                    <h4>Подписка</h4>
                    <form class="footer-subscribe" action="#" method="post">
                        <input type="email" placeholder="Ваш email" required />
                        <button type="submit" class="btn btn-primary btn-sm">OK</button>
                    </form>
                </div>
            </div>
            <div class="custom-footer__bottom">
                <p>&copy; <?php echo date('Y'); ?> Первый Бит. Все права защищены.</p>
                <div class="custom-footer__legal">
                    <a href="/privacy-policy/">Политика конфиденциальности</a>
                    <a href="/consent/">Согласие на обработку данных</a>
                </div>
            </div>
        </div>
    </div>
    <?php
}, 5);
  • Step 3: Добавить CSS футера и контактов

Добавить в style.css:

/* ==========================================================================
   Страница контактов
   ========================================================================== */

.page-contacts {
    padding: 60px 0;
}

.contacts-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 48px;
    margin-top: 32px;
}

.contacts-info p {
    line-height: 1.8;
}

.contacts-form input,
.contacts-form textarea {
    width: 100%;
    padding: 12px 16px;
    font-family: var(--font-body);
    font-size: 1rem;
    border: 2px solid var(--color-gray-light);
    border-radius: 0;
    margin-bottom: 12px;
    box-sizing: border-box;
}

.contacts-form input:focus,
.contacts-form textarea:focus {
    outline: none;
    border-color: var(--color-primary);
}

/* ==========================================================================
   Футер
   ========================================================================== */

.custom-footer {
    border-top: 1px solid var(--color-gray-light);
    padding: 48px 0 24px;
}

.custom-footer__grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1.5fr;
    gap: 32px;
    margin-bottom: 32px;
}

.custom-footer__col h4 {
    font-size: 0.875rem;
    margin: 0 0 16px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.custom-footer__col ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.custom-footer__col li {
    margin-bottom: 8px;
    font-size: 0.875rem;
}

.custom-footer__col a {
    color: var(--color-gray-text);
}

.custom-footer__col a:hover {
    color: var(--color-primary);
}

.custom-footer__col p {
    font-size: 0.875rem;
    color: var(--color-gray-text);
    line-height: 1.6;
}

.footer-subscribe {
    display: flex;
    gap: 8px;
}

.footer-subscribe input {
    flex: 1;
    padding: 8px 12px;
    font-size: 0.875rem;
    border: 2px solid var(--color-gray-light);
    border-radius: 0;
}

.custom-footer__bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 24px;
    border-top: 1px solid var(--color-gray-light);
    font-size: 0.75rem;
    color: var(--color-gray-text);
}

.custom-footer__legal {
    display: flex;
    gap: 24px;
}

.custom-footer__legal a {
    color: var(--color-gray-text);
    font-size: 0.75rem;
}

@media (max-width: 767px) {
    .contacts-grid {
        grid-template-columns: 1fr;
    }

    .custom-footer__grid {
        grid-template-columns: 1fr;
    }

    .custom-footer__bottom {
        flex-direction: column;
        gap: 12px;
        text-align: center;
    }
}
  • Step 4: Создать страницу "Контакты" в WP, назначить шаблон

  • Step 5: Проверить контакты и футер

  • Step 6: Коммит

git add themes/bitwms-child/
git commit -m "feat: add contacts page template and custom footer"

Task 13: Формы Contact Form 7 и gated-контент

Контекст: Настраиваем реальные формы CF7 для всех точек лидогенерации. Gated-контент для материалов.

Файлы:

  • Создать: wp-content/themes/bitwms-child/js/gated-content.js

  • Модифицировать: wp-content/themes/bitwms-child/inc/enqueue.php

  • Step 1: Создать формы Contact Form 7 в админке

В админке WP > Contact > Add New. Создать 5 форм:

Форма "Заказать демо":

[text* your-name placeholder "Имя"]
[text your-company placeholder "Компания"]
[tel* your-phone placeholder "Телефон"]
[email* your-email placeholder "Email"]
[textarea your-comment placeholder "Комментарий"]
[acceptance consent] Согласен на [обработку персональных данных](/privacy-policy/) [/acceptance]
[submit "Отправить заявку"]

Форма "Получить консультацию":

[text* your-name placeholder "Имя"]
[tel* your-phone placeholder "Телефон"]
[email* your-email placeholder "Email"]
[textarea your-question placeholder "Ваш вопрос"]
[acceptance consent] Согласен на [обработку персональных данных](/privacy-policy/) [/acceptance]
[submit "Отправить"]

Форма "Зарегистрироваться":

[text* your-name placeholder "Имя"]
[email* your-email placeholder "Email"]
[tel your-phone placeholder "Телефон"]
[acceptance consent] Согласен на [обработку персональных данных](/privacy-policy/) [/acceptance]
[submit "Зарегистрироваться"]

Форма "Скачать материал" (gated):

[text* your-name placeholder "Имя"]
[email* your-email placeholder "Email"]
[hidden material-id]
[acceptance consent] Согласен на [обработку персональных данных](/privacy-policy/) [/acceptance]
[submit "Скачать"]

Форма "Обратная связь":

[text* your-name placeholder "Имя"]
[email* your-email placeholder "Email"]
[textarea* your-message placeholder "Сообщение"]
[acceptance consent] Согласен на [обработку персональных данных](/privacy-policy/) [/acceptance]
[submit "Отправить"]

Для каждой формы настроить email-уведомление на адрес wms@1bit.ru.

  • Step 2: Заменить placeholder-формы на шорткоды CF7

Обновить шаблоны page-bit-wms.php, page-contacts.php — заменить HTML-формы на echo do_shortcode('[contact-form-7 id="ID" title="Название"]'); с реальными ID форм.

  • Step 3: Создать JS для gated-контента

Создать файл wp-content/themes/bitwms-child/js/gated-content.js:

/**
 * Gated-контент — модальное окно для скачивания материалов за email
 */
document.addEventListener('DOMContentLoaded', function () {
    var modal = document.getElementById('gated-modal');
    if (!modal) return;

    var overlay = modal.querySelector('.gated-modal__overlay');
    var closeBtn = modal.querySelector('.gated-modal__close');

    // Открытие модального окна по data-gated
    document.addEventListener('click', function (e) {
        var trigger = e.target.closest('[data-gated]');
        if (!trigger) return;

        e.preventDefault();
        var materialId = trigger.dataset.gated;
        var downloadUrl = trigger.dataset.downloadUrl;

        // Установить hidden-поле с ID материала
        var hiddenField = modal.querySelector('input[name="material-id"]');
        if (hiddenField) {
            hiddenField.value = materialId;
        }

        // Сохранить URL для скачивания
        modal.dataset.downloadUrl = downloadUrl || '';

        modal.classList.add('gated-modal--open');
        document.body.style.overflow = 'hidden';
    });

    // Закрытие
    function closeModal() {
        modal.classList.remove('gated-modal--open');
        document.body.style.overflow = '';
    }

    if (closeBtn) closeBtn.addEventListener('click', closeModal);
    if (overlay) overlay.addEventListener('click', closeModal);

    // После успешной отправки CF7 — скачать файл
    document.addEventListener('wpcf7mailsent', function (e) {
        if (modal.classList.contains('gated-modal--open') && modal.dataset.downloadUrl) {
            window.open(modal.dataset.downloadUrl, '_blank');
            closeModal();
        }
    });
});
  • Step 4: Добавить HTML модального окна в footer

Добавить в functions.php:

// Модальное окно gated-контента
add_action('wp_footer', function () {
    ?>
    <div id="gated-modal" class="gated-modal">
        <div class="gated-modal__overlay"></div>
        <div class="gated-modal__content">
            <button class="gated-modal__close" aria-label="Закрыть">&times;</button>
            <h3>Скачать материал</h3>
            <p>Укажите ваши данные для получения доступа к материалу</p>
            <?php // echo do_shortcode('[contact-form-7 id="ID" title="Скачать материал"]'); ?>
        </div>
    </div>
    <?php
});
  • Step 5: Добавить CSS модального окна

Добавить в style.css:

/* ==========================================================================
   Модальное окно (gated-контент)
   ========================================================================== */

.gated-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    align-items: center;
    justify-content: center;
}

.gated-modal--open {
    display: flex;
}

.gated-modal__overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
}

.gated-modal__content {
    position: relative;
    background: var(--color-white);
    padding: 48px;
    max-width: 480px;
    width: 90%;
    z-index: 1;
}

.gated-modal__close {
    position: absolute;
    top: 16px;
    right: 16px;
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--color-gray-text);
}
  • Step 6: Подключить скрипт в enqueue.php

Добавить в inc/enqueue.php:

    // Gated-контент
    wp_enqueue_script(
        'bitwms-gated-content',
        $theme_uri . '/js/gated-content.js',
        [],
        $theme_version,
        true
    );
  • Step 7: Проверить формы и gated-контент

  • Step 8: Коммит

git add themes/bitwms-child/
git commit -m "feat: add Contact Form 7 forms and gated content modal"

Task 14: Попапы, JivoSite, callback, аналитика

Контекст: Финальный слой лидогенерации: попапы (exit-intent, таймер), виджеты JivoSite и callback, аналитика.

Файлы:

  • Модифицировать: wp-content/themes/bitwms-child/functions.php

  • Step 1: Настроить Popup Maker

В админке WP > Popup Maker > Add New:

Попап "Exit-intent — Подписка":

  • Содержимое: "Не уходите! Подпишитесь на экспертные материалы по складской логистике" + форма email
  • Триггер: Exit Intent
  • Условия: все страницы
  • Настройки: показывать 1 раз за сессию

Попап "Таймер — Демо":

  • Содержимое: "Хотите увидеть БИТ.WMS в действии?" + CTA "Заказать демо"

  • Триггер: Time Delay — 60 секунд

  • Условия: только страница БИТ.WMS

  • Настройки: показывать 1 раз за сессию

  • Step 2: Подключить JivoSite

Добавить в functions.php:

// JivoSite — виджет онлайн-консультанта
add_action('wp_footer', function () {
    // Подставить реальный widget_id из кабинета JivoSite
    ?>
    <!-- JivoSite -->
    <script src="//code.jivo.ru/widget/XXXXXXXX" async></script>
    <?php
}, 99);

Настройка автоприглашения через 30 сек — в панели управления JivoSite (Настройки > Проактивные приглашения), указать страницы: главная, /bit-wms/, /cases/.

  • Step 3: Подключить callback-виджет

Добавить в functions.php:

// Callback-виджет
add_action('wp_footer', function () {
    // Подставить реальный код виджета из кабинета callback-hunter или аналога
    ?>
    <!-- Callback Widget -->
    <!-- <script src="https://cdn.callbackhunter.com/XXXXX.js" async></script> -->
    <?php
}, 99);
  • Step 4: Подключить Яндекс.Метрику и GA4

Добавить в functions.php:

// Аналитика — Яндекс.Метрика + GA4
add_action('wp_head', function () {
    ?>
    <!-- Yandex.Metrika counter -->
    <!-- Подставить реальный ID счётчика -->
    <!--
    <script type="text/javascript">
       (function(m,e,t,r,i,k,a){...})(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
       ym(XXXXXXXX, "init", {
            clickmap:true,
            trackLinks:true,
            accurateTrackBounce:true,
            webvisor:true
       });
    </script>
    -->

    <!-- Google Analytics 4 -->
    <!-- Подставить реальный ID GA4 -->
    <!--
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'G-XXXXXXXXXX');
    </script>
    -->
    <?php
}, 1);

Цели в Яндекс.Метрике настраиваются через интерфейс метрики после получения ID счётчика.

  • Step 5: Настроить Yoast SEO

В админке WP > SEO > General:

  • Указать название организации: "Первый Бит"
  • Schema.org: тип организации — Company
  • Social: указать ссылки на VK, Telegram

Для каждой страницы/записи: заполнить SEO-заголовок и мета-описание.

  • Step 6: Проверить все виджеты

  • JivoSite виджет отображается в правом нижнем углу

  • Попап exit-intent срабатывает при уходе с сайта

  • Попап таймера появляется через 60 сек на странице БИТ.WMS

  • Step 7: Коммит

git add themes/bitwms-child/
git commit -m "feat: add popups, JivoSite, callback widget, and analytics tracking"

Task 15: Финальная проверка и полировка

Контекст: Проверяем весь сайт целиком: все страницы, формы, адаптивность, производительность.

  • Step 1: Проверить все страницы

Пройти по каждой странице и убедиться:

  • Главная: герой, фильтр, лента, промо WMS, подписка, клиенты

  • БИТ.WMS: герой, функции, "почему", кейсы, другие решения, демо-форма

  • Архивы: кейсы, статьи, вебинары, курсы, мероприятия, материалы

  • Детальные: каждый тип записи с ACF-полями

  • Контакты: информация + форма

  • Футер: на всех страницах

  • Step 2: Проверить адаптивность

Протестировать все страницы на разрешениях:

  • Desktop: 1920px, 1440px, 1280px
  • Tablet: 1024px, 768px
  • Mobile: 375px, 320px

Убедиться:

  • Боковая панель скрывается < 768px, гамбургер работает

  • Сетки переходят в 1 колонку

  • Формы занимают полную ширину

  • Текст читабелен

  • Step 3: Проверить формы

Отправить тестовые данные через каждую форму:

  • Заказать демо
  • Получить консультацию
  • Зарегистрироваться на вебинар
  • Скачать материал (gated)
  • Обратная связь

Убедиться что email-уведомления приходят.

  • Step 4: Проверить производительность
# Установить плагин кеширования (опционально)
wp plugin install wp-super-cache --activate

Проверить в Google PageSpeed Insights или Lighthouse:

  • Целевые показатели: LCP < 2.5s, CLS < 0.1

  • Шрифты загружаются с font-display: swap

  • Изображения оптимизированы

  • Step 5: Создать страницы юридических документов

wp post create --post_type=page --post_title='Политика конфиденциальности' --post_name='privacy-policy' --post_status=publish
wp post create --post_type=page --post_title='Согласие на обработку персональных данных' --post_name='consent' --post_status=publish

Заполнить юридический текст (предоставляется заказчиком).

  • Step 6: Финальный коммит
git add themes/bitwms-child/
git commit -m "chore: final polish - responsive fixes, performance, legal pages"