При разработке и развитии сайта на WordPress иногда приходится решать задачи, которые на первый взгляд кажутся довольно простыми. Например, перенести произвольные поля из одного раздела JetEngine в другой.
Но если за этими полями уже стоят десятки страниц, динамические шаблоны Elementor, изображения, повторители и реальные данные, обычный перенос превращается в полноценную миграцию.
Расскажу, как я решал такую задачу на сайте MRKT Group, почему пришлось разработать собственный WordPress-плагин и какую роль в этом сыграл ChatGPT.
С чего всё началось
На сайте используется WordPress в связке с Elementor Pro и плагинами Crocoblock, в частности JetEngine.
Для управления услугами создан отдельный тип записи — «Услуги» (uslugy).
Со временем в нём накопилось 129 произвольных полей. Они использовались для самых разных блоков страниц: заголовков, описаний, изображений, стоимости услуг, преимуществ, этапов работ, FAQ и других элементов.
Сами поля были разделены по смыслу на два больших направления: разработка сайтов и SEO-продвижение.
Но все 129 определений находились непосредственно внутри настроек одного типа записи JetEngine.
Работать с такой структурой стало неудобно. Чтобы изменить одно поле, приходилось искать его среди большого количества других. Кроме того, в перспективе я планировал дальше расширять структуру услуг и добавлять новые блоки.
Решение напрашивалось само собой — перенести поля в отдельные метабоксы JetEngine.
В результате хотелось получить:
- Отдельный метабокс для услуг разработки сайтов.
- Отдельный метабокс для SEO-услуг.
- Сохранение существующих названий и ключей полей.
- Сохранение всех текстов, изображений, повторителей и других данных.
- Возможность продолжать использовать существующие динамические шаблоны Elementor и JetEngine.
И всё это без ручного пересохранения каждой записи.
Первая неожиданность — поля и их значения хранятся отдельно
Первоначально задача казалась простой: скопировать определения полей из CPT в нужные метабоксы, сохранить их meta_key, после чего удалить старые определения.
Однако обнаружилась важная особенность.
У типа записи «Услуги» был включён режим Custom Meta Storage.
Это означает, что JetEngine хранил значения произвольных полей не в стандартной таблице WordPress wp_postmeta, а в отдельной таблице wp_uslugy_meta.
В то же время обычные метабоксы JetEngine используют стандартное хранилище метаданных WordPress.
Получилась интересная ситуация.
После копирования определений в новые метабоксы ранее заполненные данные ещё отображались. Но при удалении исходных определений из CPT значения в метабоксах становились пустыми.
Один из способов исправить это — открыть каждую услугу и пересохранить запись. Тогда значения записываются в новое хранилище.
Но делать это вручную для десятков записей и сотен значений мне совершенно не хотелось.
Стало понятно, что нужно переносить не только структуру полей, но и сами данные.
Собственный плагин для миграции JetEngine
Для решения задачи я использовал ChatGPT как помощника в разработке и анализе кода.
В результате появился собственный служебный WordPress-плагин — MRKT JetEngine Metabox Migrator.
Идея заключалась в том, чтобы сделать инструмент, который сможет работать непосредственно со структурой JetEngine и при этом минимизировать риск потери данных.
Плагин получил возможность выбирать нужный тип записи, отмечать поля через чекбоксы, выполнять массовое выделение, искать поля по meta_key, копировать определения в существующие метабоксы и предварительно показывать изменения.
Отдельно был реализован механизм переноса значений из Custom Meta Storage в wp_postmeta.
Причём обычного копирования оказалось недостаточно. Понадобились проверки фактического наличия столбцов в БД, сравнение значений, обнаружение конфликтов и создание резервных копий операций.
По мере тестирования плагин несколько раз дорабатывался. Последней используемой в этом процессе стала версия 1.2.2, в которой появилась подробная диагностика несовпадающих значений.
Разделение 129 полей по метабоксам
Сначала я изучил экспорт конфигурации JetEngine и определил, какие поля относятся к каждому направлению.
В итоге структура распределилась следующим образом:
| Направление | Количество полей |
|---|---|
| Разработка сайтов | 58 |
| SEO-продвижение | 71 |
| Всего | 129 |
При этом выяснилось, что 22 определения являются служебными элементами интерфейса — вкладками и аккордеонами.
Оставшиеся 107 — поля, которые действительно могут хранить значения: текст, изображения, списки, переключатели, повторители и другие данные.
Все исходные поля были скопированы в соответствующие метабоксы с сохранением ключей и параметров.
Это было особенно важно, поскольку Elementor и JetEngine используют meta_key при динамическом выводе контента. Сохранение существующих ключей позволяет избежать массового изменения привязок в шаблонах.
Массовый перенос значений между таблицами
Следующим этапом стала работа непосредственно с базой данных.
Плагин проверил реальные столбцы в wp_uslugy_meta, исключил служебные элементы, для которых не требуется хранить значения, и подготовил перенос в стандартную таблицу wp_postmeta.
Предварительная диагностика показала:
| Показатель | Результат |
|---|---|
| Найдено строк Custom Storage | 38 |
| Полей для проверки | 107 |
| Непустых значений | 1602 |
| Пустых значений | 2464 |
| Конфликтов перед копированием | 0 |
Большое количество пустых значений оказалось нормальным: не все поля используются на каждой странице услуги.
Например, поля, относящиеся к SEO-продвижению, могут быть пустыми у услуг разработки сайтов и наоборот.
После предварительной проверки я выполнил массовое копирование значений непосредственно в wp_postmeta.
Но на этом история не закончилась.
Четыре конфликта, которые оказались самой интересной частью задачи
После копирования я повторно запустил проверку.
Большинство значений совпали, но плагин обнаружил четыре расхождения.
На первый взгляд было непонятно, почему они появились: новые значения уже находились в wp_postmeta, но отличались от исходных.
Пришлось разобраться подробнее.
В миграторе появилась отдельная диагностическая таблица, показывающая ID записи, meta_key, размеры значений и контрольные суммы SHA-256.
Затем я сравнил данные непосредственно в phpMyAdmin.
Три конфликта оказались связаны с HTML-разметкой заголовков.
В старой версии данных использовались теги <div> и <p>, а в актуальной — <span>.
Тут я вспомнил, что действительно когда-то переделывал HTML-разметку этих заголовков.
То есть в стандартной таблице WordPress сохранились старые варианты контента, а в Custom Meta Storage — новые.
Четвёртый конфликт оказался ещё интереснее.
Он возник в поле-повторителе nomer_zagolovok_opisanie, где хранился сериализованный PHP-массив.
В одной версии текста использовались символы • и неразрывные пробелы, а в другой — HTML-сущности • и .
Внешне содержимое было практически одинаковым, но на уровне базы данных отличалось.
После проверки я определил, что актуальные значения находятся именно в wp_uslugy_meta.
Поэтому вместо глобальной перезаписи всех полей исправил четыре конкретных значения с помощью адресных SQL-запросов.
Это позволило сохранить нужный контент, не затрагивая остальные данные.
Финальная проверка: 1602 совпадения и ни одного конфликта
После устранения расхождений я снова запустил предпросмотр миграции.
На этот раз получил ожидаемый результат:
1602 значения совпадают с исходными, 0 конфликтов, 0 значений осталось скопировать.
Таким образом, все непустые значения из выбранных 107 полей были перенесены в стандартное хранилище WordPress и прошли проверку на совпадение.
Особенно важно, что значения переносились без ручного пересохранения каждой услуги. Исходная таблица Custom Meta Storage при этом сохранилась.
Проверка включала не только обычные текстовые поля, но и изображения, HTML-содержимое и сериализованные повторители.
После синхронизации данных можно переходить к заключительной очистке структуры CPT — удалению дублирующих определений полей. Эту операцию необходимо выполнять с резервной копией и контрольной проверкой динамического вывода Elementor и JetEngine.

Что получилось в результате
Основная техническая задача решена: определения полей распределены по тематическим метабоксам, а данные синхронизированы между хранилищами.
Вместо работы с одним огромным списком из 129 полей появилась более удобная структура, разделённая на разработку сайтов и SEO.
При этом удалось:
- Сохранить существующие
meta_key. - Перенести 1602 непустых значения.
- Найти и устранить четыре расхождения между таблицами.
- Избежать ручного пересохранения десятков услуг.
- Подготовить безопасный механизм для дальнейшей очистки исходных полей.
- Получить собственный инструмент миграции JetEngine с предпросмотром и диагностикой.
Отдельно о работе с ChatGPT
В этом кейсе ChatGPT был не просто инструментом для написания отдельных фрагментов PHP-кода.
ChatGPT помог: проанализировал устройства JetEngine, доработал плагин, в поиске причин ошибок, в подготовке диагностических SQL-запросов и проверке логики переноса.
При этом реальные операции выполнял я сам: работал с настройками WordPress, делал резервные копии, переносил определения, запускал проверки, анализировал значения в базе данных и принимал решения о том, какую версию данных нужно сохранить.
Такой подход оказался продуктивным: ИИ помогал разрабатывать и проверять технические решения, а фактическое состояние сайта и корректность результата контролировались отдельно.
Вывод
Этот случай ещё раз показал, что перенос произвольных полей WordPress — это не всегда простое копирование настроек.
Особенно когда используется JetEngine с Custom Meta Storage, а на сайте уже накопилось много динамического контента.
Важно понимать, где физически находятся значения, как они связаны с ключами полей и что произойдёт при изменении их определений.
В результате вместо ручной рутинной работы я получил управляемый процесс миграции с резервным копированием, предпросмотром, диагностикой и проверкой данных.
И самое главное — все 1602 перенесённых значения совпали с исходными.
Стек: WordPress, Elementor Pro, JetEngine, Crocoblock, PHP, JavaScript, MySQL 8.0, phpMyAdmin, ChatGPT.




