Last days we encountered an issue where images of a product from import script weren`t properly updated.
After several hours of researching we ended with custom workflow for updating product images programmatically:

$_product = $this->_imageHelper->updateImages($_product,$imagesData,$imagesUrls);

it points to a custom image helper where we are including those dependencies

public function __construct(
        Context $context,
        \Magento\Catalog\Model\Product\Gallery\EntryFactory $entryFactory,
        \Magento\Catalog\Model\Product\Gallery\Entry $entry,
        \Magento\Framework\Api\ImageContentFactory $contentFactory,
        \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
    )
    {
        $this->_mediaEntryFactory = $entryFactory;
        $this->_mediaEntry = $entry;
        $this->_productRepository = $productRepository;
        $this->_contentFactory = $contentFactory;
        parent::__construct($context);
    }

after that we call our main function


/**
     * @param $product
     * @param $imagesData
     * @param $urls
     * @return mixed
     * @throws \Magento\Framework\Exception\CouldNotSaveException
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\StateException
     */
    public function updateImages($product,$imagesData,$urls){
        /** 1. Download new images and save them to temp folder @see TEMP_IMAGES_PATH */
        $this->downloadImages($urls);
        /** 2. Delete existing media Entries */
        $product = $this->deleteExistingMediaEntries($product);
        /** 3. Update with new images */
        $product = $this->updateProductMediaEntry($product,$imagesData);
        /** 4. Delete temp images saved in temporary folder */
        $this->deleteImages($urls);

        return $product;
    }

we are interested in deleteExistingMediaEntries which deletes existing media entries from the product

protected function deleteExistingMediaEntries($product){
        $mediaGalleryEntries = $product->getMediaGalleryEntries();

        foreach ($mediaGalleryEntries as $key => $imageObject){
            unset($mediaGalleryEntries[$key]);
         }

        $product->setMediaGalleryEntries($mediaGalleryEntries);

        $this->_productRepository->save($product);

        return $product;
    }

it is important to use

$this->_productRepository->save($product);

after the delete becouse it persist the settings

and the functions updateProductMediaEntry and createMediaEntry.
The first one is creating an Magento object in which is holded information about our new media entry like Media type , Name or Content.
The seccond one iterates through $imagesData variable which holds info about prepared images to be included in the product , after that we are setting the created in this way new media entries into magento product media gallery and save it.

/**
     * @param array $imgData
     * @return null
     */
    protected function createMediaEntry($imgData = []){

        if(empty($imgData)){
            return null;
        }

        $entry = $this->_mediaEntryFactory->create();
        $entry->setFile($imgData['path'])
            ->setMediaType($imgData['type'])
            ->setDisabled(false)
            ->setTypes($imgData['types']);

        $imageContent = $this->_contentFactory->create();
            $imageContent->setType(mime_content_type($imgData['path']))
                    ->setName(basename($imgData['path']))
                    ->setBase64EncodedData(base64_encode(file_get_contents($imgData['path'])));
        $entry->setContent($imageContent);

        return $entry;

    }

    /**
     * @param $product
     * @param $imagesData
     * @return mixed
     * @throws \Magento\Framework\Exception\CouldNotSaveException
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\StateException
     */
    protected function updateProductMediaEntry($product,$imagesData){

        $mediaGalleryEntries = [];

        if(!empty($imagesData['smallImages'])){
            foreach ($imagesData['smallImages'] as $imageFileName) {
                if (@is_array(getimagesize(self::TEMP_IMAGES_PATH . $imageFileName))) {
                    $mediaGalleryEntries[] = $this->createMediaEntry([
                        'path' => self::TEMP_IMAGES_PATH . $imageFileName,
                        'type'=>'image',
                        'types'=>[
                            'small_image'
                        ],
                    ]);
                }
            }
        }

        if(!empty($imagesData['images'])){
            foreach ($imagesData['images'] as $imageFileName) {
                if (@is_array(getimagesize(self::TEMP_IMAGES_PATH . $imageFileName))) {
                    $mediaGalleryEntries[] = $this->createMediaEntry([
                        'path' => self::TEMP_IMAGES_PATH . $imageFileName,
                        'type'=>'image',
                        'types'=>[
                            'images'
                        ],
                    ]);
                }
            }
        }

        if(isset($imagesData['baseImage'])){
            if (@is_array(getimagesize(self::TEMP_IMAGES_PATH . $imagesData['baseImage']))) {
                $mediaGalleryEntries[] = $this->createMediaEntry([
                    'path' => self::TEMP_IMAGES_PATH . $imagesData['baseImage'],
                    'type'=>'image',
                    'types'=>[
                        'image', 'small_image', 'thumbnail'
                    ]
                ]);
            }
        }

        $product->setMediaGalleryEntries($mediaGalleryEntries);
        $this->_productRepository->save($product);

        return $product;
    }

After that we are returning back to our main import class

Leave a Reply

Your email address will not be published. Required fields are marked *

Fork us on GitHub