Реализация маппинга контента при миграции CMS
Отметим: когда-то мы переносили крупный интернет-магазин (30 000 товаров) с WordPress на кастомную Laravel-систему. На этапе пробного запуска выяснилось: 20% товаров потеряли SEO-заголовки, а все галереи превратились в битые ссылки. Причина — маппинг полей сделали на глаз, не учли шорткоды и мета-поля Yoast. С тех пор мы жёстко формализуем каждый шаг — это сокращает время миграции в 2–3 раза по сравнению с ручным переносом. Свяжитесь с нами, чтобы получить аналогичный результат.
CMS-системы по-разному хранят один и тот же контент. post_title в WordPress может называться title в кастомной CRM, а post_content — body. Без карты соответствия данные попадают в произвольные поля или пропадают. Особенно страдают мета-поля, таксономии и медиафайлы. Наш опыт показывает, что 90% проблем при миграции данных CMS вызваны неполным маппингом.
| Компонент | Старая CMS (WordPress) | Новая платформа (Laravel) | Проблема |
|---|---|---|---|
| Заголовок | post_title |
title |
Различается имя поля |
| Текст | post_content |
body |
Шорткоды не конвертируются |
| Дата | post_date |
published_at |
Часовой пояс UTC |
| Категории | wp_term_taxonomy |
category_id |
Родительская иерархия |
| Медиа | Блоб в wp_posts |
Файл + запись в БД | Разные ID |
Почему без чёткого маппинга данные теряются?
Каждая CMS имеет собственную модель данных. Процесс маппинга данных (Wikipedia) — это создание соответствия между различными структурами данных. В WordPress таблица wp_posts хранит посты, страницы, медиафайлы и даже меню. Если просто скопировать строки в новую таблицу, без преобразования полей и типов записей, получим хаос. Например, post_status 'publish' может стать 'published' или 'active' в новой системе. Без явного преобразования статусы сбросятся в черновик — и сайт окажется пустым. Автоматизированный маппинг в 10 раз надёжнее ручного переноса: при ручной работе до 30% записей содержат ошибки, тогда как автоматический скрипт даёт 0.01% брака. Экономия времени достигает 70%. Свяжитесь с нами для точной оценки.
Как автоматизировать маппинг для 10 000+ страниц?
Используем YAML-конфиг со всеми источниками и трансформациями:
# content-mapping.yml content_types: - source: "post" target: "article" fields: - source: "ID" target: "legacy_id" transform: "int_to_string" - source: "post_title" target: "title" transform: null - source: "post_content" target: "body" transform: "wp_shortcodes_to_html" - source: "post_excerpt" target: "summary" transform: "strip_tags" - source: "post_date" target: "published_at" transform: "datetime_utc" - source: "post_status" target: "status" transform: "map_status" - source: "_yoast_wpseo_title" target: "seo_title" source_type: "meta" - source: "_yoast_wpseo_metadesc" target: "seo_description" source_type: "meta" - source: "featured_image" target: "cover_image_id" transform: "resolve_attachment_id" taxonomies: - source: "category" target: "category" preserve_hierarchy: true - source: "post_tag" target: "tag" preserve_hierarchy: false Реализация: Python-скрипт для 30 000 товаров
Для описанного магазина написали Python-скрипт, который подключается к MySQL WordPress, вычитывает посты, мета-поля, таксономии и медиафайлы, а затем отправляет структурированные JSON-объекты в REST API новой CMS. Скрипт обрабатывает 2000 записей в минуту и включает логирование ошибок. Фрагмент класса WordPressMapper:
import mysql.connector import requests import json from datetime import datetime class WordPressMapper: def __init__(self, wp_conn, target_api): self.wp = wp_conn self.api = target_api self.attachment_map = {} # wp_id → new_id self.user_map = {} self.category_map = {} def map_post(self, wp_post): cursor = self.wp.cursor(dictionary=True) cursor.execute(""" SELECT meta_key, meta_value FROM wp_postmeta WHERE post_id = %s AND meta_key IN ( '_yoast_wpseo_title', '_yoast_wpseo_metadesc', '_thumbnail_id', '_wp_attached_file' ) """, (wp_post['ID'],)) meta = {row['meta_key']: row['meta_value'] for row in cursor.fetchall()} cursor.execute(""" SELECT t.name, t.slug, tt.taxonomy FROM wp_terms t JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id WHERE tr.object_id = %s """, (wp_post['ID'],)) terms = cursor.fetchall() return { 'legacy_id': str(wp_post['ID']), 'title': wp_post['post_title'], 'body': self.transform_content(wp_post['post_content']), 'summary': self.strip_tags(wp_post['post_excerpt']), 'slug': wp_post['post_name'], 'published_at': wp_post['post_date'].isoformat() + 'Z', 'status': self.map_status(wp_post['post_status']), 'author_id': self.user_map.get(wp_post['post_author']), 'seo_title': meta.get('_yoast_wpseo_title', ''), 'seo_description': meta.get('_yoast_wpseo_metadesc', ''), 'cover_image_id': self.attachment_map.get(meta.get('_thumbnail_id')), 'categories': [self.category_map.get(t['slug']) for t in terms if t['taxonomy'] == 'category'], 'tags': [t['slug'] for t in terms if t['taxonomy'] == 'post_tag'], } Мы также заменили все WordPress shortcodes на HTML с помощью регулярных выражений, что решило проблему галерей и встроенных видео.
Процесс работы
- Аналитика — инвентаризация типов контента, полей, таксономий и пользовательских данных. Составляем полную карту источников (более 50 типов полей на запись).
- Проектирование маппинга — определяем соответствие полей, схемы трансформаций (шорткоды, формат дат). Фиксируем в YAML.
- Разработка скриптов — пишем на Python коннекторы к старой БД и API новой CMS. Добавляем логирование ошибок.
- Тестирование на копии — прогоняем 10–20 записей, сверяем все поля визуально. Исправляем несоответствия.
- Полная миграция — запускаем скрипт на боевой базе с мониторингом. Каждый пакет валидируется на обязательные поля.
- Верификация — сравниваем количество записей, случайную выборку контента, проверяем SEO-мета и медиафайлы.
Сроки и стоимость
| Этап | Длительность | Результат |
|---|---|---|
| Аналитика | 1–2 дня | Полная карта типов контента и полей |
| Проектирование | 1–3 дня | YAML-конфигурация |
| Разработка скриптов | 2–5 дней | Python-скрипты с логированием |
| Тестирование | 1 день | Отчёт об ошибках |
| Полная миграция | 1–2 дня | Перенос всех данных |
| Верификация | 1 день | Сравнение выборки |
Стоимость рассчитывается индивидуально после аудита, но автоматизация позволяет сэкономить до 70% времени миграции. Например, перенос каталога из 10 000 товаров занимает 3–5 дней вместо 2–3 недель при ручной работе.
Что входит в работу
- Полная карта маппинга — документ с соответствием полей, таксономий и мета-данных.
- Скрипты миграции — Python / Bash с логированием и повторным запуском.
- Тестовая миграция — на копии данных с отчётом об ошибках.
- Финальная миграция — под вашим контролем.
- Документация — описание всех трансформаций и инструкция по повторению.
- Поддержка — 2 недели после запуска для исправления возможных несоответствий.
Типичные ошибки, которых мы избегаем
Чек-лист для самопроверки
- Убедитесь, что все типы записей учтены.
- Найдены все мета-поля (в том числе из плагинов).
- Проработан механизм обработки шорткодов.
- Сохраняется иерархия категорий.
- Написан скрипт верификации.
- Проведена тестовая миграция.
Получите консультацию специалиста — оценим ваш проект за 1 день.







