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

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


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->getResource()->saveAttribute($product, 'custom_attributte');

if your value in array then implode()

  • 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
    Jan 21, 2015 at 17:08
  • array should take option id and it format like array(4,8,9)
    – Amit Bera
    Jan 21, 2015 at 17:10
  • see at magento.stackexchange.com/questions/3356/…
    – Amit Bera
    Jan 21, 2015 at 17:27
  • Is there a way to not use the save() for 'categoryIds' when setting them for the products? Oct 25, 2016 at 20:45

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



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

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

        if (!empty($ids)) {
                array('custom_attribute' => 'xxxx'),

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .