I need to do a massive update of product data but what I need to do can't be achieved with product import. In example I need to update media gallery and categories for given products, but the solution I came out with takes too long.

A little recap: I added a command to the Magento 2 CLI that, given a json configuration file, removes, adds, updates or sorts media gallery entries for a given product like this. Here I paste an excerpt of the code:

/* $product is of type Magento\Catalog\Model\Product */

//get existing media gallery
$existingMediaGallery = $product->getMediaGallery();

   do stuff with media gallery (alter $existingMediaGallery)
   (add, remove, sort, ...)

//set media gallery again

//process media gallery
$mediaGalleryEntries = $product->getMediaGalleryEntries();
$this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
if ($mediaGalleryEntries) {
  foreach ($mediaGalleryEntries as $k => $entry) {
    if (!isset($entry['removed']) && !empty($entry['types'])) {
      $this->getMediaGalleryProcessor()->setMediaAttribute($product, $entry['types'], $entry['file']);

//save product

Since it's a massive update the "$product->save()" line is called many times and always takes from 2 to 4 seconds. Since I need to launch the code for thousands of products I need a faster way to do that.

I tried with

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


$product->addAttributeUpdate('media_gallery', $mediaGallery, $storeId);

but that doesn't work for media gallery (only works for eav I think).

Is there a way to save only media gallery and persisting these changes faster?

(What I look for is something like Magento\Catalog\Api\CategoryLinkManagementInterface::assignProductToCategories method that saves category/product association faster than a full product save)

  • Sorry guys, I don't have any mean of testing proposed answers since this project was discontinued and I'm not developing Magento solutions anymore.
    – CaNNaDaRk
    Commented Feb 7, 2022 at 20:03

4 Answers 4


As far as I know there isn't a way to save media entries without saving product. but the save product shouldn't take very long at all with the productRepositoryInterface.

I created a similar module and I don't have the same issue with media save.

Here is my solution for save media:

     * Add Product media from folder.
     * @param $product
     * @param $productData
     * @return mixed
    protected function setProductMedia($product, $productData)
        $medias = [];
        $files = scandir(self::MEDIA_PATH);
        $mediaPath = '';
        foreach ($files as $file) {
            if ($file !== '.' && $file !== '..') {
                $path = realpath(self::MEDIA_PATH . $file);
                if ($path) {
                    if (basename($path, '.jpg') == trim($productData['productCode'])) {
                        $mediaPath = self::MEDIA_PATH . $file;

        if ((bool)$mediaPath) {
            $image = $this->_imageContent

            $media = $this->_productAttributeMediaGalleryEntry
               ->setTypes(['thumbnail', 'small_image', 'image'])

            $medias[] = $media;

        return $product;

I then save the product with the productRepositoryInterface.

   try {
        $product = $this->_productRepository->get($productData['productCode']);
    } catch (NoSuchEntityException $e) {
        throw new NoSuchEntityException(__('Could Not Update Product Error: %1', $e->getMessage()));

    $product = $this->setProductMedia($product, $productData);

    try {
    } catch (InputException $exception) {
       $this->_logger->critical(__("Could not save product Error: %1", $exception->getMessage()));
    } catch (StateException $exception) {
       $this->_logger->critical(__("Could not save product, Error: %1",$exception->getMessage()));
    } catch (CouldNotSaveException $exception) {
       $this->_logger->critical(__('Could Not Save Product Error: %1' ,$exception->getMessage()));

It saves pretty quickly. I can run 10,000 products within a few minutes. That includes the search for the media that is named as the {sku}.jpg and all stuffed in a single folder.

  • is it possible to just set image roles i.e. ->setTypes(['thumbnail', 'small_image', 'image']) without replacing the entire image?
    – paj
    Commented Sep 7, 2019 at 10:21
  • @djfordz I understand that you're setting the same source image to be used for the Base, small & thumbnail image - but would this mean the Thumbnail image be using the same size/dimensions as the the Primary photo or this'll be resized upon save?
    – MackieeE
    Commented Jun 2, 2021 at 13:21

Herve's answer hints at another way of doing this. CreateHandler is used for new product records whereas UpdateHandler is for existing products.

/* @var $product Magento\Catalog\Model\Product */
/* @var $updateHandler Magento\Catalog\Model\Product\Gallery\UpdateHandler */
/* @var $imageFile string (fully qualified path ideally) */

// 'swatch_image' is another possible type and your store could have others
$imageTypes = ['image','small_image','thumbnail'];

// params are: ($file, $mediaAttribute = null, $move = false, $exclude = true)
// when move is false the file is copied instead
// when exclude is true the image is added but disabled
$product->addImageToMediaGallery($imageFile, $imageTypes, false, false);

// this line saves the media gallery without saving whole product

I think you are on the right track: the save product is taking long and needs to go..

Now, with images update, that can be really tricky. But I'd like to think it may be a way forward to separate the problem:

  • my guess is you need the media data to be stored in the database and that can be done by using your method saveAttribute.. (very fast). However, you may want to add some attributes in your update script: see attributes 'image, small_image, thumbnail' (see in database select * from eav_attribute where ((attribute_code like '%image%') or (attribute_code='thumbnail')) and entity_type_id=4))

  • now the more complex but yet I may have some ideas, is to deal with the image physically speaking and possible extra media data (image tag title, position and so on)

--> for this second point: I'd look at the class Magento\Catalog\Model\Product\Gallery\CreateHandler as it will show you how Magento keeps it all working regarding the media data.


Use GalleryManagementInterface to modify an entry.

$entries = $this->galleryManagement->getList($sku);
foreach ($entries as $entry) {
    $entry->setLabel('Test New Label ' . $entry->getId());
    // important: unset the file path to bypass Magento strict checking for file contents.
    $this->galleryManagement->update($sku, $entry);

This helps people that only want to update an existing media gallery entry without loading the image into memory, this addresses the request said by @paj in the comments.

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.