Как перенести сайт на WordPress
Недавно передо мной встала задача перенести корпоративный сайт с самописной CMS на WordPress. Клиент хотел упростить управление контентом, а я получил отличный опыт, которым сейчас поделюсь. Расскажу без прикрас — с граблями, на которые наступил, и решениями, которые нашёл.
Подготовительный этап: не бросайтесь сразу переносить
Первое, что я сделал — составил полную карту сайта. Выгрузил структуру URL через Screaming Frog (можно использовать любые бесплатные аналоги), определил все посадочные страницы с трафиком через Яндекс Метрику и Яндекс Вебмастер. Это очень важно так как если после переноса потеряются URL с органическим трафиком, вы получите просадку по позициям в поиске на недели, а то и на месяцы.
Также я сделал бэкап исходного сайта — полный, включая базу данных и файлы. Даже если перенос идёт «с нуля», старая версия должна быть доступна для сверки контента (мало ли клиент предъявит, «что то забыли перенести»).
Шаг 1. Установка WordPress
Установил WordPress на хостинге через встроенный автоустановщик. Можно так же установить вручную, вот моя статья как это сделать, там описаны разные способы — Установка WordPress.
Шаг 2. Перенос контента
Здесь есть три сценария, и я проходил через все три в разных проектах.
Если старый сайт на WordPress — всё просто. Использую плагин All-in-One WP Migration или Duplicator. Экспортирую полный пакет со старого сайта, импортирую на новый. Занимает 10-15 минут для простого сайта.
Если сайт на другой CMS с базой данных — пишу скрипт-парсер на PHP, который вытягивал контент из базы данных старой системы и записывал в WordPress через wp_insert_post(). Пример упрощённого скрипта:
<?php
// Подключение к старой базе данных
$host = 'localhost';
$dbname = 'db_name';
$user = 'db_user';
$password = 'db_password';
$old_db = new PDO(
"mysql:host={$host};dbname={$dbname};charset=utf8mb4",
$user,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
// Получаем все посты из старой базы
$old_posts = $old_db->query("SELECT * FROM articles");
// Подключаем системный файл WordPress, он загружает основные функции
require_once('wp-load.php');
foreach ($old_posts as $post) {
$post_id = wp_insert_post([
'post_title' => $post['title'],
'post_content' => $post['body'],
'post_status' => 'publish',
'post_date' => $post['created_at'],
'post_type' => 'post'
]);
// Сохраняем старый URL как meta для будущих редиректов
update_post_meta($post_id, '_old_url', $post['slug']);
}
Если сайт статичный HTML — самый трудоёмкий вариант. Тут нужно руками разбирать каждую страницу, вычленять контент из вёрстки и переносить через админку.
Шаг 3. Настройка редиректов — самый важный шаг для SEO
Это то, о чём многие забывают, а потом теряют трафик. Я составил таблицу соответствия: старый URL → новый URL. Для этого использовал Google таблицы, куда выгрузил все страницы с трафиком за последние 12 месяцев.
Редиректы настраивал через .htaccess (если хостинг на Apache):
RewriteEngine On
Redirect 301 /old-page.html /new-page/
Redirect 301 /catalog/item123 /product/item123-new-name/
Для большого количества редиректов (у меня было около 400 URL) удобнее использовать плагин Redirection (Перенаправление) — он даёт визуальный интерфейс и логирует 404-ошибки, показывая, какие страницы реально запрашивают пользователи и боты.
Шаг 4. Перенос медиафайлов
Изображения и документы связанные с постам загружаю через медиабиблиотеку WordPress, чтобы ими можно было управлять через админку.
Шаг 5. Перенос темы
Тут придется немного поработать руками.
Самая частая ошибка новичков — пытаться «натянуть» HTML на готовую тему через визуальный редактор. Это работает плохо и недолго. Правильный путь — создать собственную тему, разбив вёрстку на шаблоны WordPress. Расскажу весь процесс пошагово.
Подготовка: что нужно перед началом
Первым делом я анализирую шаблон старого сайта и выделяю повторяющиеся блоки: хедер, футер, сайдбар, если есть. Это будущие отдельные файлы темы.
Открываю index.html и мысленно (или маркером в блокноте) размечаю: где начинается контент конкретной страницы, а где — общие элементы, которые встречаются на всех страницах.
Структура папки темы на WordPress
Создаю папку в /wp-content/themes/ с названием темы, например my-custom-theme. Внутри создаю такую структуру:
my-custom-theme/
│
├── style.css
├── functions.php
├── index.php
├── header.php
├── footer.php
├── sidebar.php
├── front-page.php
├── page.php
├── single.php
├── archive.php
├── 404.php
├── screenshot.png
│
├── assets/
│ ├── css/
│ │ └── main.css
│ ├── js/
│ │ └── main.js
│ ├── img/
│ └── fonts/
│
└── parts/
├── content.php
├── content-page.php
└── navigation.php
1. Файл style.css — обязательная шапка темы
Без этого файла WordPress не увидит тему в списке доступных. В самом верху файла прописываю метаданные:
/*
Theme Name: My Custom Theme
Theme URI: https://webexo.ru
Author: Webexo
Author URI: https://webexo.ru
Description: Тема на основе старого HTML-сайта
Version: 1.0
License: GNU General Public License v2 or later
Text Domain: my-custom-theme
*/
Весь остальной CSS из старого сайта я не пихаю сюда, а подключаю отдельным файлом через functions.php — это удобнее для поддержки.
2. functions.php — подключение стилей и скриптов
Здесь регистрирую все ресурсы, которые были в HTML-версии:
function my_theme_enqueue_scripts() {
// Основной CSS из старого сайта
wp_enqueue_style('main-style', get_template_directory_uri() . '/assets/css/main.css');
// Стили темы
wp_enqueue_style('theme-style', get_stylesheet_uri());
// JS файл
wp_enqueue_script('main-js', get_template_directory_uri() . '/assets/js/main.js',
array('jquery'), '1.0', true);
}
add_action('wp_enqueue_scripts', 'my_theme_enqueue_scripts');
// Поддержка миниатюр записей
add_theme_support('post-thumbnails');
// Поддержка меню
function my_theme_register_menus() {
register_nav_menu('primary', __('Главное меню'));
register_nav_menu('footer', __('Меню в футере'));
}
add_action('init', 'my_theme_register_menus');
// Регистрация сайдбара, если он был в HTML
function my_theme_widgets_init() {
register_sidebar(array(
'name' => __('Основной сайдбар'),
'id' => 'sidebar-1',
'before_widget' => '<div class="widget">',
'after_widget' => '</div>',
));
}
add_action('widgets_init', 'my_theme_widgets_init');
Все <link> и <script> теги из исходного HTML нужно убрать из вёрстки — они теперь подключаются через этот файл.
3. Разбиваем HTML на header.php и footer.php
Беру исходный HTML-файл и смотрю, где заканчивается повторяющийся хедер (обычно это всё до открывающего тега основного контента, <main> или <div class=»content»>).
header.php — всё от <!DOCTYPE html> до открытия основного контента, пример:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php wp_title(); ?></title>
<?php wp_head(); ?>
</head>
<body>
<header class="site-header">
<div class="logo">
<a href="<?php echo home_url(); ?>">
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/logo.png" alt="Логотип">
</a>
</div>
<nav class="main-nav">
<?php wp_nav_menu(array('theme_location' => 'primary', 'menu_class' => 'nav-list'));
?>
</nav>
</header>
<main class="site-content">
Важный момент — wp_head() обязателен, без него не будут подключаться скрипты плагинов и мета-теги.
footer.php — всё от закрытия контента до конца документа:
</main>
<footer class="site-footer">
<div class="footer-widgets">
<?php if (is_active_sidebar('footer-widgets')) : ?>
<?php dynamic_sidebar('footer-widgets'); ?>
<?php endif; ?>
</div>
<nav class="footer-nav">
<?php wp_nav_menu(array('theme_location' => 'footer')); ?>
</nav>
<p class="copyright">© <?php echo date('Y'); ?> Все права защищены</p>
</footer>
<?php wp_footer(); ?>
</body>
</html>
wp_footer() тоже обязателен — сюда плагины и WordPress выводят скрипты, которые должны загружаться в конце страницы.
4. index.php — базовый шаблон
Это шаблон-заглушка, который используется, если WordPress не находит более специфичный файл. Собираю его из header и footer плюс цикл вывода записей:
<?php get_header(); ?>
<div class="content-area">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<article <?php post_class(); ?>>
<h2><?php the_title(); ?></h2>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
<?php endwhile; ?>
<?php else : ?>
<p>Ничего не найдено.</p>
<?php endif; ?>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
5. front-page.php — главная страница
Здесь я вставляю ту часть исходного HTML, которая относится именно к содержимому главной страницы — hero-блок, преимущества, слайдер и т.д.:
<?php get_header(); ?>
<section class="hero-block">
<h1>Заголовок главной страницы</h1>
<p>Подзаголовок или описание</p>
<a href="#" class="btn-primary">Призыв к действию</a>
</section>
<section class="features">
<?php
$features = new WP_Query(array(
'post_type' => 'feature',
'posts_per_page' => 3
));
if ($features->have_posts()) :
while ($features->have_posts()) : $features->the_post();
?>
<div class="feature-item">
<?php the_title('<h3>', '</h3>'); ?>
<?php the_excerpt(); ?>
</div>
<?php
endwhile;
wp_reset_postdata();
endif;
?>
</section>
<?php get_footer(); ?>
6. page.php и single.php — для статичных страниц и статей блога
Здесь вставляю ту часть вёрстки, которая была на внутренних страницах старого сайта (например, «О нас», «Услуги»):
<?php get_header(); ?>
<div class="page-content-wrapper">
<?php while (have_posts()) : the_post(); ?>
<h1 class="page-title"><?php the_title(); ?></h1>
<?php if (has_post_thumbnail()) : ?>
<div class="page-thumbnail">
<?php the_post_thumbnail('large'); ?>
</div>
<?php endif; ?>
<div class="entry-content">
<?php the_content(); ?>
</div>
<?php endwhile; ?>
</div>
<?php get_footer(); ?>
7. sidebar.php, если в HTML был боковой блок
<aside class="site-sidebar">
<?php if (is_active_sidebar('sidebar-1')) : ?>
<?php dynamic_sidebar('sidebar-1'); ?>
<?php else : ?>
<p>Виджеты не добавлены</p>
<?php endif; ?>
</aside>
8. 404.php — страница ошибки
Беру из старого сайта дизайн страницы 404, если она была, либо создаю простую:
<?php get_header(); ?>
<div class="error-404-page">
<h1>404</h1>
<p>Страница не найдена</p>
<a href="<?php echo home_url(); ?>">Вернуться на главную</a>
</div>
<?php get_footer(); ?>
Финальный шаг: перенос изображений и медиа
Все изображения из старой вёрстки копирую в assets/images/ внутри темы, если это элементы дизайна (логотип, иконки, фоновые картинки).
Проверка результата
После сборки всех файлов активирую тему через админку и прохожу по каждому типу страниц — главная, внутренняя страница, страница 404, архив блога. Сверяю с оригинальным HTML построчно через инструменты разработчика в браузере, чтобы убедиться, что вёрстка не съехала и все классы CSS применились корректно.
Такой подход, хоть и требует времени на начальном этапе, даёт полностью рабочую, лёгкую тему без лишнего кода, который тянут за собой готовые темы.
Шаг 6. Проверка перед запуском
Перед тем как переключить DNS на новый сайт, я:
- Проверяю все формы обратной связи и их отправку на почту.
- Прогоняю сайт через инструмент проверки скорости (PageSpeed Insights).
- Устанавливаю SSL-сертификат и настраиваю принудительный HTTPS.
- Проверяю файл robots.txt и sitemap.xml (генерирую через Yoast SEO или Rank Math SEO).
- Тестирую мобильную версию на реальных устройствах.
Шаг 7. Запуск и мониторинг
После переключения DNS я не расслаблялся ещё две недели. Ежедневно проверяю Яндекс Вебмастер и Google Search Console на предмет ошибок сканирования, отслеживаю позиции ключевых запросов и логи сервера на предмет всплеска 404-ошибок.
Выводы
Перенос сайта на WordPress — это не просто техническая задача копирования файлов. Это возможность пересмотреть структуру сайта, оптимизировать URL и улучшить SEO. Но именно из-за этой возможности легко наделать ошибок, если подходить к переносу небрежно.
Мой главный совет: тратьте на планирование и подготовку столько же времени, сколько на сам техническый перенос. Именно на этапе аудита старого сайта и составления карты редиректов закладывается успех всего проекта.