0

I'm trying to load the product images of related products on the category list.phtml without loading the complete product model (to increase performance).

My current code in list.phtml is this:

 <?php $relatedProducts = $_product->getRelatedProducts(); ?>
                    <?php if(!empty($relatedProducts)): ?>
                    <div class="left-carousel">
                        <div class="product-small-thumbs">
                            <div class="carousel carousel-<?php $_product->getId()?>">
                                <?php $i = 0 ?>
                                <?php foreach($relatedProducts as $relatedProduct): ?>
                                    <?php $i++ ?>
                                    <?php if($i < 5): ?>
                                    <div class="slide">
                                    <?php
                                    $relatedProductId = $relatedProduct->getId();
                                    $relatedProduct = $block->getProductById($relatedProductId);
                                    $resizedImageBig = $block->resizeImage($relatedProduct, 'product_base_image', 460, 460)->getUrl();
                                    $resizedImageSmall = $block->resizeImage($relatedProduct, 'product_base_image', 90, 90)->getUrl();
                                    $relatedProductUrl = $relatedProduct->getUrlKey();
                                    ?>
                                        <img data-id="smallthumbs-<?php echo $_product->getId();?>"
                                         data-img="<?php echo $resizedImageBig; ?>" data-img_def=""
                                         src="<?php echo $resizedImageSmall; ?>"/>
                                    </div>

                                    <?php endif; ?>
                                <?php endforeach; ?>
                            </div>
                        </div>

Notice the getproductbyId function which loads the complete product:

public function getProductById($id)
{
    return $this->_productRepository->getById($id);
}

Is there away to avoid loading the complete product? I think that my current code is bad for performance. The preferred way would be to only load the resized/cached product main image.

Solution I've used @Sohel Rana answer to solve this problem and this worked very good. However this didn't give me the resized/cached images, so I used a separate module for this: staempfli/magento2-module-image-resizer

You can find it here: https://packagist.org/packages/staempfli/magento2-module-image-resizer

Final code:

<?php $resizerHelper = $block->getImageResizerHelper(); ?>
<?php $relatedProducts = $_product->getRelatedProducts(); ?>
                    <?php if(!empty($relatedProducts)): ?>
                    <div class="left-carousel">
                        <div class="product-small-thumbs">
                            <div class="carousel carousel-<?php $_product->getId()?>">
                                <?php $i = 0 ?>
                                <?php foreach($relatedProducts as $relatedProduct): ?>
                                    <?php $i++ ?>
                                    <?php if($i < 5): ?>
                                    <div class="slide">
                                    <?php
                                    $relatedProductId = $relatedProduct->getId();
                                    $images = $block->getImageFromDB($relatedProductId);
                                    $first_image = $images[0]['image'];
                                    $first_image_url = $block->getFullImageUrl($first_image);
                                    $resized_image_large = $resizerHelper->resizeAndGetUrl($first_image_url, 460, 460);
                                    $resized_image_small = $resizerHelper->resizeAndGetUrl($first_image_url, 90, 90);
                                    $relatedProductUrl = $relatedProduct->getUrlKey();
                                    ?>
                                        <img data-id="smallthumbs-<?php echo $_product->getId();?>"
                                         data-img="<?php echo $resized_image_large ?>" data-img_def=""
                                         src="<?php echo $resized_image_small ?>"/>
                                    </div>
                                    <?php endif; ?>
                                <?php endforeach; ?>
                            </div>
                        </div>
3

You can try following way:

public function __construct(
    \Magento\Framework\App\ResourceConnection $resourceConnection
) {
    $this->resourceConnection = $resourceConnection;

}

And now:

$productId = 2;
$connection = $this->resourceConnection->getConnection();
$select = $connection->select()
    ->from('catalog_product_entity_media_gallery_value', '*')
    ->join(
        'catalog_product_entity_media_gallery',
        'catalog_product_entity_media_gallery_value.value_id=catalog_product_entity_media_gallery.value_id',
        array('image' => 'value')
    )
    ->where('entity_id = ?', $productId);

$images = $connection->fetchAll($select);
echo '<pre>';print_r($images);echo '</pre>';
  • good idea!!!!.. – Amit Bera Apr 19 '17 at 9:29
  • @Sohel Rana this works great, thanks! What do you think about fetching the direct product image url (example: /media/catalog/product/k/a/ka5599gd.jpg) and not the cached/resized image url? – Tjitse Apr 19 '17 at 12:47
2

Alternatively to Sohel's answer you could use the getMediaGallery method from Magento\CatalogImportExport\Model\Export\Product and if needed modify it to fit your needs:

/**
 * Prepare products media gallery
 *
 * @param  int[] $productIds
 * @return array
 */
protected function getMediaGallery(array $productIds)
{
    if (empty($productIds)) {
        return [];
    }
    $select = $this->_connection->select()->from(
        ['mgvte' => $this->_resourceModel->getTableName('catalog_product_entity_media_gallery_value_to_entity')],
        [
            "mgvte.{$this->getProductEntityLinkField()}",
            'mgvte.value_id'
        ]
    )->joinLeft(
        ['mg' => $this->_resourceModel->getTableName('catalog_product_entity_media_gallery')],
        '(mg.value_id = mgvte.value_id)',
        [
            'mg.attribute_id',
            'filename' => 'mg.value',
        ]
    )->joinLeft(
        ['mgv' => $this->_resourceModel->getTableName('catalog_product_entity_media_gallery_value')],
        '(mg.value_id = mgv.value_id AND mgv.store_id = 0)',
        [
            'mgv.label',
            'mgv.position',
            'mgv.disabled'
        ]
    )->where(
        "mgvte.{$this->getProductEntityLinkField()} IN (?)",
        $productIds
    );

    $rowMediaGallery = [];
    $stmt = $this->_connection->query($select);
    while ($mediaRow = $stmt->fetch()) {
        $rowMediaGallery[$mediaRow[$this->getProductEntityLinkField()]][] = [
            '_media_attribute_id' => $mediaRow['attribute_id'],
            '_media_image' => $mediaRow['filename'],
            '_media_label' => $mediaRow['label'],
            '_media_position' => $mediaRow['position'],
            '_media_is_disabled' => $mediaRow['disabled'],
        ];
    }

    return $rowMediaGallery;
}

It takes an array of product ids as the only parameter, thus you can call that method before your loop with all your product ids and get the related media galleries.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.