HowTo: Update Product Attributes in Magento 2


I once had to update a single attribute on thousands of products from a data import. My first instinct was to load each product with the repository, set the value and save it, and it worked… but it was painfully slow. Loading and saving a full product just to change one attribute is a lot of wasted work. There is a much better tool for this.

The slow way (fine for one product)

If you only need to touch one product, the repository is perfectly fine and the most readable option:

php
<?php
$product = $this->productRepository->get('sku-123');
$product->setData('my_attribute', 'new value');
$this->productRepository->save($product);

The fast way (for many products)

When you need to update the same attribute on a lot of products, use Magento\Catalog\Model\Product\Action. It writes straight to the attribute tables without loading the whole product model, so it is dramatically faster.

php
<?php
/** app/code/Vendor/Module/Model/AttributeUpdater.php */
namespace Vendor\Module\Model;

use Magento\Catalog\Model\Product\Action;
use Magento\Store\Model\Store;

class AttributeUpdater
{
    /**
     * @var Action
     */
    private $productAction;

    /**
     * @param Action $productAction
     */
    public function __construct(Action $productAction)
    {
        $this->productAction = $productAction;
    }

    /**
     * @param int[] $productIds
     * @param array $attributes  e.g. ['my_attribute' => 'new value']
     * @param int   $storeId
     */
    public function update(array $productIds, array $attributes, $storeId = Store::DEFAULT_STORE_ID)
    {
        $this->productAction->updateAttributes($productIds, $attributes, $storeId);
    }
}

And calling it:

php
$this->attributeUpdater->update([12, 34, 56], ['my_attribute' => 'new value']);
Notice: updateAttributes() sets the value for the given store scope. Pass Store::DEFAULT_STORE_ID (0) to update the default/global value, or a specific store id to override it per store view.
Whichever way you choose, remember that changing values that affect the storefront (price, visibility, status) will schedule a reindex. On a big catalog run your indexers afterwards so the changes show up.

Hope this helps.

If you have any question or know a better way to achieve this, feel free to share in the comments below.