Kategorien in Magento exportieren und importieren

Es ist eine vielgestellte Frage und Antworten gibt es für ab 10 Euro bei Magento-Connect. Des Weiteren gibt es eine kostenlose Lösung, die bei mir aber nicht funktioniert hat. Und irgendwann bin ich auf diesen kleinen Blog gestoßen, der eine Lösung zum selberschreiben angeboten hat. Jetzt kann ich in Magento alle Kategorien exportieren und wieder importieren. Ein paar Handgriffe sind aber noch nötig gewesen.

Hier gibt es den Code, der als Ausgangsbasis diente.

Der läuft aber erstmal nicht. Ein Parserfehler, den ich mit Hilfe von Novastorm erst lösen konnte und dann gibt es Probleme, wenn die Beschreibungen HTML beinhalten, womit der Delimiter “ nicht mehr funktioniert. Fertig und funktionstüchtig sieht das Programm dann so aus:

Der Exporter

Den Exporter legt man ganz gewöhnlich in das Hauptverzeichnis der Magento-Installation. Nicht vergessen, ihn wieder zu entfernen, da hat jeder Zugriff 😉

<?php
ini_set("memory_limit","1000M");
require_once "app/Mage.php";
umask(0);
Mage::app();
$category = Mage::getModel ( 'catalog/category' );
$tree = $category->getTreeModel ();
$tree->load();
$ids = $tree->getCollection()->getAllIds();
if ($ids) {
    $string='';
    $heading = "'store','categories','cat_id','is_active','meta_title','meta_keywords','meta_description','include_in_menu','is_anchor','description',";
    foreach ($ids as $id) {
        if($id>0)//start if removeroot category and default category .
        {

            $cate_cre = Mage::getModel('catalog/category');

            $cate_cre->load($id);
            $treeurl='';
            $cate_cre1=Mage::getModel('catalog/category')->load($id);
            $treeurl=$cate_cre->getName();
            if($cate_cre1->getParentId()>0)
            {
                for($i=0; ;$i++)
                {
                    if($cate_cre1->getParentId()>0)
                    {
                        $abc=Mage::getModel('catalog/category')->load($cate_cre1->getParentId());
                        $pCat=$abc->getName();
                        if($abc->getId()>1){
                            $treeurl=$pCat.'/'.$treeurl;
                        }
                        $cate_cre1=$abc;
                    }
                    else{
                        break;
                    }
                }
            }
            $store = "default";
            $string .= "'".$store."','".$treeurl."','".$id."','".$cate_cre->getIsActive()."','".$cate_cre->getMetaTitle()."','".$cate_cre->getMetaKeywords()."','".$cate_cre->getMetaDescription()."','".$cate_cre->getIncludeInMenu()."','".$cate_cre->getIsAnchor()."','".$cate_cre->getDescription()."'";
            $string.="\n";
        }//endof if removeroot category and default category .
    }
    $csv_output = $heading ."\n".$string;
    $filename = "Categories";
    header("Content-type: application/vnd.ms-excel");
    header("Content-disposition: csv" . date("Y-m-d") . ".csv");
    header( "Content-disposition: filename=".$filename.".csv");
    print $csv_output;
}

Hier sind die Anpassungen wegen des Delimiters.

Der Importer

Der Importer selbst wird hier

/app/code/local/ImpCat/Catalog/Model/Convert/Adapter/

gespeichert und heißt

Category.php

Der Inhalt:

<?php
class ImpCat_Catalog_Model_Convert_Adapter_Category
    extends Mage_Eav_Model_Convert_Adapter_Entity
{
    protected $_categoryCache = array();

    protected $_stores;

    /**
     * Category display modes
     */
    protected $_displayModes = array( 'PRODUCTS', 'PAGE', 'PRODUCTS_AND_PAGE');

    public function parse()
    {
        $batchModel = Mage::getSingleton('dataflow/batch');
        /* @var $batchModel Mage_Dataflow_Model_Batch */

        $batchImportModel = $batchModel->getBatchImportModel();
        $importIds = $batchImportModel->getIdCollection();

        foreach ($importIds as $importId) {
            //print '<pre>'.memory_get_usage().'</pre>';
            $batchImportModel->load($importId);
            $importData = $batchImportModel->getBatchData();

            $this->saveRow($importData);
        }
    }

    /**
     * Save category (import)
     *
     * @param array $importData
     * @throws Mage_Core_Exception
     * @return bool
     */
    public function saveRow(array $importData)
    {
        if (empty($importData['store'])) {
            if (!is_null($this->getBatchParams('store'))) {
                $store = $this->getStoreById($this->getBatchParams('store'));
            } else {
                $message = Mage::helper('catalog')->__('Skip import row, required field "%s" not defined', 'store');
                Mage::throwException($message);
            }
        } else {
            $store = $this->getStoreByCode($importData['store']);
        }

        if ($store === false) {
            $message = Mage::helper('catalog')->__('Skip import row, store "%s" field not exists', $importData['store']);
            Mage::throwException($message);
        }

        $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()];

        $importData['categories'] = preg_replace('#\s*/\s*#', '/', trim($importData['categories']));
        if (!empty($cache[$importData['categories']])) {
            return true;
        }

        $path = $rootPath;
        $namePath = '';

        $i = 1;
        $categories = explode('/', $importData['categories']);
        /*$IsActive = $importData['IsActive'];*/
        $IsActive = $importData['is_active'];
        $IsAnchor =$importData['is_anchor'];
        $Description =$importData['description'];
        $IncludeInMenu=$importData['include_in_menu'];
        $MetaTitle=$importData['meta_title'];

        $MetaKeywords=$importData['meta_keywords'];
        $MetaDescription=$importData['meta_description'];
        $Image=$importData['image'];
        $URlkey=$importData['url_key'];

        foreach ($categories as $catName) {
            $namePath .= (empty($namePath) ? '' : '/').strtolower($catName);
            if (empty($cache[$namePath])) {

                $dispMode = $this->_displayModes[2];
                $cat = Mage::getModel('catalog/category')
                    ->setStoreId($store->getId())
                    ->setPath($path)
                    ->setName($catName)
                    ->setIsActive($IsActive)
                    ->setIsAnchor($IsAnchor)
                    ->setDisplayMode($dispMode)->save();

                $cat = Mage::getModel('catalog/category')->load($cat->getId());
                $cat->setIncludeInMenu($IncludeInMenu);
                $cat->setDescription($Description);
                $cat->setMetaTitle($MetaTitle).
                $cat->setMetaKeywords($MetaKeywords);
                $cat->setMetaDescription($MetaDescription);
                $cat->save();

                $cat = Mage::getModel('catalog/category')->load($cat->getId());
                $data['meta_keywords']=$MetaKeywords;
                $data['meta_title']=$MetaTitle;
                $data['meta_keywords']=$MetaKeywords;
                $data['meta_description']=$MetaDescription;
                $data['url_key']= $URlkey;
                $cat->addData($data);
                $cat->save();
                $cache[$namePath] = $cat;
            }
            $catId = $cache[$namePath]->getId();
            $path .= '/'.$catId;
            $i++;
        }



        return true;
    }

    /**
     * Retrieve store object by code
     *
     * @param string $store
     * @return Mage_Core_Model_Store
     */
    public function getStoreByCode($store)
    {
        $this->_initStores();
        if (isset($this->_stores[$store])) {
            return $this->_stores[$store];
        }
        return false;
    }

    /**
     * Init stores
     *
     * @param none
     * @return void
     */
    protected function _initStores ()
    {
        if (is_null($this->_stores)) {
            $this->_stores = Mage::app()->getStores(true, true);
            foreach ($this->_stores as $code => $store) {
                $this->_storesIdCode[$store->getId()] = $code;
            }
        }
    }
}

Der ist Quasi 1:1 übernommen und verrichtet seinen Dienst wie erwartet.

Das Modul brauch eine Config. Diese landet in

/app/code/local/ImpCat/Catalog/etc/

und heißt

config.xml

Der Inhalt:

<?xml version="1.0"?>
<config>
    <modules>
        <Import_Catalog>
            <version>0.1.0</version>
        </Import_Catalog>
    </modules>
    <global>
        <models>
            <impcat>
                <class>ImpCat_Catalog_Model</class>
            </impcat>
        </models>
    </global>
</config>

Hier geht mein Dank an Novastorm, die einen Fehler in der XML gefunden haben.

Um das Modul zu aktivieren muss noch eine weitere XML-Datei angelegt werden:

/app/etc/modules/

Name:

ImpCat_All.xml

Inhalt:

<?xml version="1.0"?>
<config>
    <modules>
        <ImpCat_Catalog>
            <codePool>local</codePool>
            <active>true</active>
        </ImpCat_Catalog>
    </modules>
</config>

Fertig. Fast 😉

Das Profil

Nun wird in Magento unter System > Import/Export > Dataflow – Erweiterte Profile ein neues Profil angelegt.

Profil Name: Frei wählbar

Action XML ist angepasst, der Delimiter stimmt nicht und der Weg zum Adapter ist falsch im Original.

<action type="dataflow/convert_adapter_io" method="load">
  <var name="type">file</var>
  <var name="path">var/import</var>
  <var name="filename"><![CDATA[Categories.csv]]></var>
  <var name="format"><![CDATA[csv]]></var>
</action>
<action type="dataflow/convert_parser_csv" method="parse">
  <var name="delimiter"><![CDATA[,]]></var>
  <var name="enclose"><![CDATA[']]></var>
  <var name="fieldnames">true</var>
  <var name="store"><![CDATA[0]]></var>
  <var name="number_of_records">1</var>
  <var name="decimal_separator"><![CDATA[.]]></var>
  <var name="adapter">impcat/convert_adapter_category</var>
  <var name="method">parse</var>
</action>

Die Ausführung

  • Zunächst die Export-Datei ausführen. Sie spuckt eine Categorys.csv aus.
  • Diese wird in den Ordner /var/import/ kopiert.
  • Nun wird das Profil ausgeführt

Das wars. Viel Spaß 🙂

Genutzt in 1.9.2.1

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.