Импорт и экспорт контента
{
"title": "Импорт и экспорт контента в WordPress: технический разбор, форматы и качество данных",
"keywords": "импорт контента WordPress, экспорт WordPress, XML-RPC, WXR, массовый перенос записей, миграция WordPress, технические форматы данных",
"description": "Подробный технический разбор процесса импорта и экспорта контента в WordPress. Рассматриваются форматы WXR, CSV, XML-RPC, требования к структуре данных, типичные ошибки и сценарии миграции.",
"html_content": "Исходная ситуация и техническая задача
Клиент — компания, занимающаяся производством корпусной мебели, владела тремя разрозненными сайтами на WordPress, каждый из которых использовал свою тему, свои типы записей и произвольные поля (ACF). Необходимо было объединить каталог продукции, включающий более 4000 товаров с техническими характеристиками, чертежами, спецификациями материалов и 3D-моделями, в единый портал. Задача осложнялась тем, что на старых сайтах использовались разные версии PHP (7.4, 8.0) и разные версии WordPress (5.8, 6.0), а также плагины, не поддерживающие стандартный WXR-формат.
Проблема была не в объёме данных, а в их гетерогенности: на одном сайте атрибуты товара хранились в сериализованных массивах в мета-полях, на втором — в кастомных таксономиях, на третьем — в виде шорткодов внутри контента. Прямой импорт через стандартный инструмент WordPress (Инструменты → Импорт) приводил к потере данных: выпадали изображения, ломались ссылки на спецификации, сбрасывались значения полей, отвечающих за ГОСТы и допуски.
Выбор протокола и формата данных
После аудита структуры баз данных было принято решение отказаться от стандартного WXR (WordPress eXtended RSS) в пользу комбинации: XML-RPC для сущностей (записи, страницы) и CSV с жёсткой схемой для метаданных. Стандартный WXR хорош только для блогов: он поддерживает основные поля (title, content, excerpt), таксономии и медиафайлы, но при попытке передать 15+ произвольных полей на каждый товар файл раздувается до гигабайтов, а парсинг на стороне приёмника виснет из-за ограничений memory_limit в 256 MB.
Для миграции была разработана многоэтапная процедура. На первом этапе выгружались все медиафайлы через FTP с сохранением структуры папок (uploads/YYYY/MM/). На втором этапе через XML-RPC с использованием библиотеки IXR_Client отправлялись базовые данные записей. Каждая запись получала новый ID на целевом сайте, а старые ID фиксировались в отдельной таблице соответствия для дальнейшей перелинковки. На третьем этапе через скрипт на Python (с обвязкой по cURL) происходил массовый импорт CSV-файлов со спецификациями в ACF-поля.
- XML-RPC — использовался для передачи базового контента (post_title, post_content, post_excerpt). Максимальный размер пакета — 10 МБ. При превышении — ошибка 500. Пришлось нарезать большие описания товаров (с таблицами и встраиваемыми 3D-моделями) на чанки.
- CSV с заголовками — для метаданных. Ключевое требование: экранирование кавычек и символов перевода строки в значениях. Использовался стандарт RFC 4180. Разделитель — запятая, кодировка — UTF-8 без BOM.
- WXR (ограниченно) — только для импорта меню и блоков виджетов через стандартный интерфейс. Потребовал ручной корректировки ссылок на страницы после смены ID.
Проблемы с целостностью данных и ссылками
Первая тестовая миграция 500 товаров выявила критическую проблему: внутренние ссылки в описаниях товаров вели на старые ID записей. Например, в поле «Комплектация» была ссылка на другой товар из этого же каталога, но на новом сайте URL изменился. Стандартные плагины типа Velvet Blues Update URLs не справлялись с кастомными полями ACF типа «ссылка».
Пришлось писать SQL-запрос для поиска и замены в сериализованных данных. Сложность заключалась в том, что ACF хранит ссылки в формате a:1:{s:4:\"url\";s:XXX:\"http://...";}. Прямая замена подстроки в сериализованном массиве ломает его — PHP перестаёт распознавать данные. Решение — скрипт на PHP, который десериализует массив, заменяет URL, а затем ресериализует обратно. Дополнительно пришлось обработать 2300 ячеек в postmeta.
Вторая проблема касалась изображений. На старом сайте пресеты для thumbnails были разных размеров (300x200, 800x600), на новом — только 3 размера. При импорте через XML-RPC WordPress пытался сгенерировать все недостающие размеры кропов, что на 4000 товарах вызвало таймауты. Решение — предварительная генерация всех метаданных изображений через скрипт wp-cli media regenerate после загрузки оригиналов.
Технические спецификации и контроль качества
После импорта каждого этапа проводилась верификация данных по трём уровням. Первый уровень — автоматическая сверка количества записей и полей между базами через SQL-запросы (SELECT COUNT(*) FROM wp_posts WHERE post_type = 'product'). Второй уровень — проверка форматов: все даты должны быть в формате Y-m-d H:i:s, все URL — абсолютные, все числа с плавающей точкой — с точкой в качестве разделителя (не запятой).
Третий уровень — выборочная проверка 5% товаров вручную. Проверялось: соответствие таксономий (материалы: МДФ, ЛДСП, массив; фурнитура: Blum, Hettich), корректность ссылок на PDF-спецификации (ГОСТы), наличие всех 3D-моделей в папке /uploads/models/. Было выявлено, что в 3% случаев имена файлов кириллицей не конвертировались в латиницу — пришлось добавить обработчик transliteration на стороне импорта.
- База данных до миграции: 4 ГБ, 18 таблиц, 4300 записей.
- База данных после миграции: 5.2 ГБ, 22 таблицы, 4120 записей (разница — за счёт очистки дублей).
- Время выполнения миграции: 18 часов с учётом ручных проверок и перезагрузки сервера (исходный хостинг — shared, целевой — VPS с 4 ГБ RAM).
Отличия от стандартных плагинов миграции
На рынке существуют десятки плагинов для импорта/экспорта (WP All Import, Export All URLs, Migrate DB Pro). Однако в промышленных сценариях с большим объёмом кастомных полей и специфическими требованиями к форматам они либо слишком медленные, либо накладывают свои правила на структуру данных. WP All Import, например, при импорте CSV-файла с 4000 строк и 20 полями создаёт временные таблицы, которые при базовом лимите innodb_buffer_pool_size в 128 MB приводят к ошибке «MySQL server has gone away».
Кроме того, стандартные инструменты не умеют обрабатывать вложенные поля ACF (группы, повторители) без дополнительных надстроек. В нашем случае в товаре использовался repeater для списка комплектующих — плагин требовал ручного маппинга XML-узлов, что при 300 повторяющихся строках на один товар делало конфигурацию нечитаемой. Только написание собственного скрипта на Python с прямой записью в wp_postmeta через INSERT минуя абстракции WordPress дало нужную скорость (15 000 строк метаданных в минуту).
Стандартные плагины не гарантируют перенос таксономий, если slug отличается. Пришлось экспортировать все термины (материалы, типы покрытия, категории фурнитуры) вместе с их иерархией через отдельный скрипт, который создавал term_taxonomy записи с заданными term_id. Это позволило сохранить ссылки на родительские категории (например, «ДСП → Ламинированная ДСП → Кромка ПВХ»).
Результаты и эксплуатационные характеристики
Итоговая структура на целевом сайте полностью повторяла исходную логическую модель, но была приведена к единым стандартам: все даты — в UNIX timestamp, все URL — относительные (для гибкости при смене домена), все изображения — с явным указанием alt-тегов и данных EXIF (ISO, выдержка, фокусное расстояние — для технической документации).
Скорость загрузки каталога после миграции (замер через Lighthouse) осталась в пределах нормы — 1.2 секунды до LCP. Критическим фактором выступило то, что при импорте не были сгенерированы дублирующиеся мета-ключи — каждая запись имела ровно один набор полей, что ускорило выборки из БД на 18% по сравнению с исходным сайтом, где из-за плагинов-накопителей (вроде Yoast SEO) в таблице postmeta было до 15 записей с ключом _yoast_wpseo_title на одну страницу.
Заказчик получил полный контроль над данными: теперь для экспорта каталога в Excel (для закупщиков мебельной фурнитуры) не нужны плагины — достаточно SQL-запроса с JOIN по postmeta. Импорт новых товаров через XML-RPC настроен как CI/CD-процесс: дизайнер загружает 3D-модель, менеджер заполняет CSV, и через cron-задачу раз в час новые позиции появляются на сайте. Ошибки в данных (неверный формат толщины материала, отсутствие файла чертежа) логируются в отдельную таблицу и отправляются в Telegram-бота.
" }Добавлено: 24.04.2026
