Files
bit-wms-site/docs/superpowers/plans/2026-04-03-bit-wms-site.md
T

3842 lines
122 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Экспертный портал БИТ.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
```bash
# Если используем 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: Установить и активировать обязательные плагины**
```bash
# Премиум-плагины устанавливаются вручную (загрузка 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**
```bash
# Постоянные ссылки: /%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-репозиторий**
```bash
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`:
```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
<?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
<?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`:
```javascript
/**
* Боковая навигация — 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: Подготовить директории для ассетов**
```bash
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: Активировать дочернюю тему и проверить**
```bash
wp theme activate bitwms-child
```
Открыть `http://bitwms.local` — тема должна активироваться, стили брендбука (цвета, шрифты) должны применяться.
- [ ] **Step 7: Коммит**
```bash
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
<?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`:
```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` (перед закрывающим `?>` или в конец):
```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: Коммит**
```bash
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`:
```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):
```html
<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`:
```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: Коммит**
```bash
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
<?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`:
```php
$bitwms_includes = [
'inc/enqueue.php',
'inc/cpt.php',
];
```
- [ ] **Step 3: Обновить permalink и проверить**
```bash
wp rewrite flush
```
В админке WP: проверить что в меню появились разделы "Кейсы", "Вебинары", "Курсы", "Мероприятия", "Материалы".
Создать рубрики для стандартных постов:
```bash
wp term create category "Статьи" --slug=articles
wp term create category "Новости" --slug=news
```
- [ ] **Step 4: Коммит**
```bash
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
<?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`:
```php
$bitwms_includes = [
'inc/enqueue.php',
'inc/cpt.php',
'inc/acf-fields.php',
];
```
- [ ] **Step 3: Проверить поля в админке**
В админке WP: открыть создание нового Кейса, Вебинара, Курса, Мероприятия, Материала — проверить что все ACF-поля отображаются корректно с нужными типами и условной логикой (например, "Запись видео" появляется только при статусе "Прошёл").
- [ ] **Step 4: Коммит**
```bash
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
<?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
<?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`:
```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: Коммит**
```bash
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
<?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
<?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
<?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`:
```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: Коммит**
```bash
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
<?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
<?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
<?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`:
```javascript
/**
* 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`:
```php
$bitwms_includes = [
'inc/enqueue.php',
'inc/cpt.php',
'inc/acf-fields.php',
'inc/ajax-filter.php',
];
```
Обновить `inc/enqueue.php` — добавить скрипт и локализацию:
```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`:
```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: Коммит**
```bash
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
<?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`:
```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: Коммит**
```bash
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
<?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
<?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`:
```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: Коммит**
```bash
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
<?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`:
```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`:
```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: Коммит**
```bash
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`:
```javascript
/**
* 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`:
```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`:
```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`:
```php
// Gated-контент
wp_enqueue_script(
'bitwms-gated-content',
$theme_uri . '/js/gated-content.js',
[],
$theme_version,
true
);
```
- [ ] **Step 7: Проверить формы и gated-контент**
- [ ] **Step 8: Коммит**
```bash
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`:
```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`:
```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`:
```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: Коммит**
```bash
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: Проверить производительность**
```bash
# Установить плагин кеширования (опционально)
wp plugin install wp-super-cache --activate
```
Проверить в Google PageSpeed Insights или Lighthouse:
- Целевые показатели: LCP < 2.5s, CLS < 0.1
- Шрифты загружаются с `font-display: swap`
- Изображения оптимизированы
- [ ] **Step 5: Создать страницы юридических документов**
```bash
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: Финальный коммит**
```bash
git add themes/bitwms-child/
git commit -m "chore: final polish - responsive fixes, performance, legal pages"
```