Превращаем цифровые ID в человекопонятное дерево категорий

Решение для WP All Import: Превращаем цифровые ID в человекопонятное дерево категорий из YML

Классическая головная боль при импорте YML-фидов (Яндекс.Маркет, СберМегаМаркет, маркетплейсы): в карточке каждого товара есть только числовой идентификатор вроде <categoryId>14882</categoryId>. Сами же названия категорий и их родительские связи лежат отдельно в начале файла в блоке <categories>.

Если передать {categoryId[1]} напрямую в WP All Import, плагин создаст рубрику с именем «14882» вместо полноценного пути «Бытовая техника > Климатическая техника > Обогреватели».

Ниже — готовое и быстрое решение, которое сопоставляет ID с реальными названиями категорий и собирает их в полную иерархию.

Почему стандартные способы тормозят или ломают Preview?

  1. В товаре нет названий. Без сопоставления с блоком <categories> плагин видит только цифры.
  2. Пустой предпросмотр (Preview). В окне Preview плагин изолирует выполнение, стандартные пути к текущему файлу часто недоступны, из-за чего кастомные функции возвращают пустоту.
  3. Падения по памяти. Если в прайсе десятки тысяч позиций (30 000–50 000+), повторный парсинг XML-дерева на каждом товаре гарантированно приводит к Fatal error: Allowed memory size exhausted или Execution timeout.

Как мы это решаем:

При первом же вызове функция находит блок <categories> в исходном XML, за доли секунды собирает карту соответствия ID => Полный путь с названиями и сохраняет её во временный файл wpallimport_cat_map.json. Для всех последующих товаров (и в окне Preview) функция просто мгновенно берет готовое название по его ID.

Шаг 1. Добавляем функцию сопоставления в плагин Code Snippets

Добавьте этот PHP-код через плагин Code Snippets (или в functions.php дочерней темы):

function get_yml_category_path($category_id) {
static $map = null;

if ($map === null) {
$upload_dir = wp_upload_dir();
$cache_file = $upload_dir['basedir'] . '/wpallimport_cat_map.json';

// 1. Проверяем кэш
if (file_exists($cache_file) && (time() - filemtime($cache_file) < 86400)) {
$map = json_decode(file_get_contents($cache_file), true);
}

// 2. Если кэша нет — парсим категории из рабочего XML
if (empty($map)) {
$map = [];
$raw_cats = [];

// Ищем исходный XML-файл в uploads/wpallimport
$import_dir = $upload_dir['basedir'] . '/wpallimport/uploads';
$files = glob($import_dir . '/*/*.xml');

// Если не нашли в подпапках, ищем последний измененный XML в uploads
if (empty($files)) {
$files = glob($upload_dir['basedir'] . '/wpallimport/*.xml');
}

if (!empty($files)) {
// Берем самый свежий файл
usort($files, function($a, $b) {
return filemtime($b) - filemtime($a);
});
$source_file = $files[0];

// Читаем блок
$handle = @fopen($source_file, 'r');
$categories_chunk = '';
if ($handle) {
while (($line = fgets($handle)) !== false) {
$categories_chunk .= $line;
if (strpos($line, '') !== false) {
break;
}
}
fclose($handle);
}

if (preg_match('/(.*?)<\/categories>/s', $categories_chunk, $matches)) {
$xml = simplexml_load_string('' . $matches[1] . '');
if ($xml) {
foreach ($xml->category as $cat) {
$id = (string)$cat['id'];
$raw_cats[$id] = [
'name' => trim((string)$cat),
'parentId' => isset($cat['parentId']) ? (string)$cat['parentId'] : null,
];
}
}
}
}

// Выстраиваем полные цепочки для каждого ID
foreach ($raw_cats as $id => $data) {
$chain = [];
$curr = $id;
$limit = 0;
while ($curr && isset($raw_cats[$curr]) && $limit < 10) { $c_name = $raw_cats[$curr]['name']; if ($c_name !== 'Все товары') { array_unshift($chain, $c_name); } $curr = $raw_cats[$curr]['parentId']; $limit++; } $map[$id] = implode(' > ', $chain);
}

// Сохраняем в кэш
if (!empty($map)) {
@file_put_contents($cache_file, json_encode($map, JSON_UNESCAPED_UNICODE));
}
}
}

$target_id = trim((string)$category_id);
return isset($map[$target_id]) ? $map[$target_id] : '';
}

Шаг 2. Настройка сопоставления в шаблоне WP All Import

Перейдите к редактированию вашего импорта на Шаг 3 (Step 3):

  1. Откройте блок Taxonomies, Categories, Tags.
  2. Отметьте таксономию Product categories (Категории товаров).
  3. Выберите переключатель: «An element in my file contains the entire hierarchy» (Элемент в моем файле содержит всю иерархию).
  4. В поле для пути категории передайте поле с ID через нашу функцию: [get_yml_category_path({categoryId[1]})]
  5. В поле Separated by (Разделитель) укажите символ с пробелами по бокам: 
  6. Нажмите Preview прямо под полем иерархии.

Что изменится?

  • Было: Товар импортировался в категорию с бессмысленным числовым именем 14882.
  • Стало: Функция принимает ID 14882, находит его в сопоставленной карте и отдает путь Бытовая техника > Климатическая техника > Обогреватели > Конвекторы.
  • Предпросмотр работает: В окне Preview цепочка сразу видна корректно.
  • Нагрузка 0%: Даже на базах в 40 000+ товаров сервер не тратит ресурсы на повторный разбор XML.
Рейтинг
( Пока оценок нет )
Владимир Ключеров/ автор статьи

Укрощаю трубы днем, вывожу сайты в топ ночью. Сантехник-практик, создатель сайтов, SEO-специалист и партнерский маркетолог.

Понравилась статья? Поделиться с друзьями:
Блог Владимира Ключерова
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: