Quick script to batch create Magento categories

A site we administer with a reasonable amount of SKUs (far in excess of 100,000), needed some quick category manipulation for a series of new data to be dropped in. The new information had a desired category tree that had to be built up quick, but with over 600 categories to be created, human effort wouldn't be suitable.

So, using the Magento category ID export script to help manipulate the CSV - we were able to quickly make a script to batch create our categories.

First off, create your CSV with 2 columns, the parent ID for the category and the category name - you could easily add more columns for extra options, but it wasn't necessary for us.

The CSV file should be something like this:

3,subcat
4,subcat2
6,subcat3

Then it should be saved in ./var/import/importCats.csv

Then save the following in `./quickCatCreate.php

<?php
define('MAGENTO', realpath(dirname(__FILE__)));
require_once MAGENTO . '/app/Mage.php';

umask(0);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$count = 0;
$file = fopen('./var/import/importCats.csv', 'r');

while (($line = fgetcsv($file)) !== FALSE)
    {
    $count++;

    // $line is an array of the csv elements

    if (!empty($line[0]) && !empty($line[1]))
        {
        $data['general']['path'] = $line[0];
        $data['general']['name'] = $line[1];
        $data['general']['meta_title'] = "";
        $data['general']['meta_description'] = "";
        $data['general']['is_active'] = "";
        $data['general']['url_key'] = "";
        $data['general']['display_mode'] = "PRODUCTS";
        $data['general']['is_anchor'] = 0;
        $data['category']['parent'] = $line[0]; // 3 top level
        $storeId = 0;
        createCategory($data, $storeId);
        sleep(0.5);
        unset($data);
        }
    }

function createCategory($data, $storeId)
    {
    echo "Starting {$data['general']['name']} [{$data['category']['parent']}] ...";
    $category = Mage::getModel('catalog/category');
    $category->setStoreId($storeId);

    // Fix must be applied to run script
    // http://www.magentocommerce.com/boards/appserv/main.php/viewreply/157328/

    if (is_array($data))
        {
        $category->addData($data['general']);
        if (!$category->getId())
            {
            $parentId = $data['category']['parent'];
            if (!$parentId)
                {
                if ($storeId)
                    {
                    $parentId = Mage::app()->getStore($storeId)->getRootCategoryId();
                    }
                  else
                    {
                    $parentId = Mage_Catalog_Model_Category::TREE_ROOT_ID;
                    }
                }

            $parentCategory = Mage::getModel('catalog/category')->load($parentId);
            $category->setPath($parentCategory->getPath());
            }

        /**
         * Check "Use Default Value" checkboxes values
         */
        if ($useDefaults = $data['use_default'])
            {
            foreach($useDefaults as $attributeCode)
                {
                $category->setData($attributeCode, null);
                }
            }

        $category->setAttributeSetId($category->getDefaultAttributeSetId());
        if (isset($data['category_products']) && !$category->getProductsReadonly())
            {
            $products = array();
            parse_str($data['category_products'], $products);
            $category->setPostedProducts($products);
            }

        try
            {
            $category->save();
            echo "Suceeded <br /> ";
            }

        catch(Exception $e)
            {
            echo "Failed <br />";
            }
        }
    }

Then it is just a matter of visiting the link in your browser to create the categories - customise to your hearts content, any further expansion should be very easy (such as product association etc.)

Uh oh - I'm getting errors after the first record!

Fatal error: Call to a member function getPath() on a non-object in appcodecoreMageCatalogModelResourceEavMysql4Category.php on line 385 

There is a small NB though, there is a bug with Magento's original code that will cause a problem with the above script, a quick fix is outlined here. It is just a matter of commenting out 2 lines to force the variable to be re-set.

In ./app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category.php line #110

protected function _getTree() {
    //if (!$this->_tree) {
    $this - > _tree = Mage::getResourceModel('catalog/category_tree') - > load();
    //}
    return $this - > _tree;
}