Import category structure with products using DataFlow
This is an old revision of the document!
Abstract |
This article will outline functionality of importing new categories and/or associating new/existing products with categories.
- The categories will be imported from field named “categories”.
- Categories should be in format “Category/Subcat1/Subcat2”.
- Category names can have whitespaces around, they will be trimmed.
- It is possible to provide multiple categories for same product line by separating them with comma.
- The lines with “categories” HAVE to have “store” field with correct values.
- UPDATED: Category names are not case-sensitive unique.
An example of import file with required fields for existing products:
"store","sku","categories" "default","FOO","Apparel/Shoes,Clearance" "default","BAR","Electronics"
Patched file for 1.1.7 |
For easy fix, download and unzip this file into app/code/local/Mage/Catalog/Model/Convert/Adapter/
Preparation for integration in extension |
You will need to follow this article: customize_part_of_configuration to overload class contained in this file: app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php
It is OK to use existing local custom extension if available.
New functionality |
In your custom overloaded class add these property and method:
- protected $_categoryCache = array();
- protected function _addCategories($categories, $store)
- {
- $rootId = $store->getRootCategoryId();
- if (!$rootId) {
- return array();
- }
- $rootPath = '1/'.$rootId;
- if (empty($this->_categoryCache[$store->getId()])) {
- $collection = Mage::getModel('catalog/category')->getCollection()
- ->setStore($store)
- ->addAttributeToSelect('name');
- $collection->getSelect()->where("path like '".$rootPath."/%'");
- foreach ($collection as $cat) {
- $pathArr = explode('/', $cat->getPath());
- $namePath = '';
- for ($i=2, $l=sizeof($pathArr); $i<$l; $i++) {
- $name = $collection->getItemById($pathArr[$i])->getName();
- $namePath .= (empty($namePath) ? '' : '/').trim($name);
- }
- $cat->setNamePath($namePath);
- }
- $cache = array();
- foreach ($collection as $cat) {
- $cache[strtolower($cat->getNamePath())] = $cat;
- $cat->unsNamePath();
- }
- $this->_categoryCache[$store->getId()] = $cache;
- }
- $cache =& $this->_categoryCache[$store->getId()];
- $catIds = array();
- foreach (explode(',', $categories) as $categoryPathStr) {
- $categoryPathStr = preg_replace('#s*/s*#', '/', trim($categoryPathStr));
- if (!empty($cache[$categoryPathStr])) {
- $catIds[] = $cache[$categoryPathStr]->getId();
- continue;
- }
- $path = $rootPath;
- $namePath = '';
- foreach (explode('/', $categoryPathStr) as $catName) {
- $namePath .= (empty($namePath) ? '' : '/').strtolower($catName);
- if (empty($cache[$namePath])) {
- $cat = Mage::getModel('catalog/category')
- ->setStoreId($store->getId())
- ->setPath($path)
- ->setName($catName)
- ->setIsActive(1)
- ->save();
- $cache[$namePath] = $cat;
- }
- $catId = $cache[$namePath]->getId();
- $path .= '/'.$catId;
- }
- if ($catId) {
- $catIds[] = $catId;
- }
- }
- return join(',', $catIds);
- }
Changing existing method |
Copy the whole public function saveRow(array $importData) into custom class and make the following change:
- // right after this:
- if (isset($importData['category_ids'])) {
- $product->setCategoryIds($importData['category_ids']);
- }
- // add this:
- if (isset($importData['categories'])) {
- $categoryIds = $this->_addCategories($importData['categories'], $store);
- if ($categoryIds) {
- $product->setCategoryIds($categoryIds);
- }
- }


