Richard Parnaby-King

Web Developer – PHP, Zend Framework and Actionscript 3

Posted on | | No Comments

Code When dealing with Magento, the common knowledge to bulk update products is to pull in a collection and, in a loop, load the product, change the attribute and save.

A client is syncing their product database from their system to Magento, but their system only allows a product to be in one category. I was asked to run a cron script nightly to check for an attribute on the product and place those products into an additional category.

Knowing how slow save() is, I started to dig around and come up with the below code.

Benchmarking this code against the regular way of doing it, I saw the times drop from about an hour and a half for 1,200 products to five seconds!

This is the minimum amount of code required to alter a collection of products to add them to a new category. I’ve removed the extra code regarding my scenario above.

// Set indexing to manual before starting updates, otherwise it'll continually get slower as you update
$processes = Mage::getSingleton('index/indexer')->getProcessesCollection();
$processes->walk('setMode', array(Mage_Index_Model_Process::MODE_MANUAL));
/** @var Varien_Db_Adapter_Pdo_Mysql **/
$dbw = Mage::getSingleton('core/resource')->getConnection('core_write');
$productCategoryTable = Mage::getSingleton('core/resource')->getTableName('catalog/category_product');
$product_ids = Mage::getModel('catalog/product')->getCollection()
$category_id = 123;
// Add product ids and category ids to database for insertion
$data = array();
foreach($product_ids as $id) {
    $data[] = array(
        'category_id' => (int)$category_id,
        'product_id'  => (int)$id,
        'position'    => 1,
if(count($data)) {
    // Updates a single attribute, much faster than calling a full product save
    try {
        $dbw->insertMultiple($productCategoryTable, $data);
    } catch (Exception $e) {
        //ignore duplicate entry error messages
        if(strpos(strtolower($e->getMessage()), 'duplicate entry') === FALSE) {
Mage::log('Products Put in Category:');
// Reindex all
// Set indexing back to realtime, if you have it set to manual normally you can comment this line out
$processes->walk('setMode', array(Mage_Index_Model_Process::MODE_REAL_TIME));

Posted By:



    Having eight years of programming experience in PHP, Zend Framework and ActionScript3, I have a very strong working knowledge of object orientated programming.

    I am a PC Gamer! Playing FPS, RTS, RPG and the occasional MMO since 1996 I have a huge number of a variety of fast-paced games.

  • Recent Posts

  • Categories