2

I need to loop through all the products in a particular category, change a custom attribute and then save each product.

Currently i have:

$_category = Mage::getModel('catalog/category')->load($_POST['id']);
$all_products = $_category->getProductCollection();

foreach ($all_products as $product) {
    $product = Mage::getModel('catalog/product')->load($product->getId());  
    $product->setCustomAttribute(xxxx);
    $product->save();
}

Is this best practice and can it be improved for performance? The collections average around 15-20 products in each and i am getting a very slow loadtime or even the script timing out.

I've used set_time_limit(0); to try and force it through but i imagine i can improve my code to stop me having to do this? Eventually the collections may have over 100-200 products each so need to find a good performance now

2 Answers 2

2

Instead of loading full product object use it resource model attribute save (getResource()->saveAttribute). It is quit quick awsy to save product data.

Set value: $product->setCustomAttribute('yourval');

Save it value using resource attribute

 $product->getResource()->saveAttribute($product, 'custom_attributte');

it only save this attribute not all attribute

Full code:

foreach ($all_products as $product) {
    $product->setCustomAttribute(xxxx);
    $product->getResource()->saveAttribute($product, 'custom_attributte');
}

if your value in array then implode()
$product->setCustomAttribute(implode(',',array()));

4
  • Thanks Amit. The custom attribute value is a multi select (so comes in as an array) - does this make a difference? Just tried and nothing was updating
    – odd_duck
    Commented Jan 21, 2015 at 17:08
  • array should take option id and it format like array(4,8,9)
    – Amit Bera
    Commented Jan 21, 2015 at 17:10
  • see at magento.stackexchange.com/questions/3356/…
    – Amit Bera
    Commented Jan 21, 2015 at 17:27
  • Is there a way to not use the save() for 'categoryIds' when setting them for the products? Commented Oct 25, 2016 at 20:45
0

Firstly, you shouldnt be accessing the $_POST super global variable directly. You should use the Magento request object for that.

Also, you shouldn't need to load the product, you already have the Mage_Catalog_Model_Product object from the collection.

Not unnecessarily re-loading the product should speed up your code quite easily.

For super performance and kind-of-correct handling of $_POST (I dont know where this code is being executed, so I'm grabbing the request object direct) you can do something like the following.

//If you're in a controller you should be able to call $this->getRequest()
$categoryId= Mage::app()->getRequest()->getPost('id');
$storeCode = 'default';

$storeId = Mage::getModel('core/store')->load($storeCode)->getId();

$_category = Mage::getModel('catalog/category')->load($categoryId);

if ($storeId && $_category->getId()) {
    $all_products = $_category->getProductCollection();

    $all_products->getSelect()->reset(Zend_Db_Select::COLUMNS)->columns('entity_id');

    $all_products->setPageSize(500);

    for ($curPage = 1; $curPage <= $all_products->getLastPageNumber(); $curPage++) {
        $all_products->clear();
        $all_products->setCurPage($curPage);

        $ids = array();
        foreach ($all_products as $product) {
            $ids[] = $product->getId();
        }

        if (!empty($ids)) {
            Mage::getSingleton('catalog/product_action')->updateAttributes(
                $ids,
                array('custom_attribute' => 'xxxx'),
                $storeId
            );
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.