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

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

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