Magento – magento2 loading upsell products

magento2up-sells

I'm trying to display upsell products on the view page. For that, I created my own custom block for the template with following code:

<?php

namespace YS\India\Block;

use Magento\Framework\App\ObjectManager;
use Magento\Catalog\Block\Product\AbstractProduct;

/**
 * Catalog product upsell items block
 *
 * @SuppressWarnings(PHPMD.LongVariable)
 */
class Upsell extends AbstractProduct
{
/**
 * @param \Magento\Catalog\Block\Product\Context $context
 * @param array $data
 */
public function __construct(
    \Magento\Catalog\Block\Product\Context $context
) {
    parent::__construct($context);
}

public function getUpSellProducts()
{
    $product = $this->_coreRegistry->registry('product');

    $upSellProductIds = $product->getUpSellProductIds();

    if(isset($upSellProductIds)){

        $products = array();
        $objectManager = ObjectManager::getInstance();

        foreach($upSellProductIds as $productId) {
            $product = $objectManager->get('Magento\Catalog\Model\Product')->load($productId);

            $products[] = $product;
        }

        return $products;
    }

    return null;
}
}

What's going with above code is this:

The following line is working fine and giving me upsell ids.

$upSellProductIds = $product->getUpSellProductIds();

The problem is after executing the loop:

foreach($upSellProductIds as $productId) {
    ....
}

the products array has same product although productId is different.

What I am missing here?

Best Answer

The main problem with your code is that you are using ObjectManager::get().
This will always return the same instance of the class you pass as parameter. It acts similar to Mage::getSingleton() in magento 1.
For a quick fix use $objectManager->create('Magento\Catalog\Model\Product').
But this is not the proper way to do it. You should use the object manager only in factories, and even there you should inject it in the constructor. You should not retrieve the instance like you do ObjectManager::getInstance();.

You should use the product factory instead.
Something like this:

<?php

namespace YS\India\Block;

use Magento\Framework\App\ObjectManager;
use Magento\Catalog\Block\Product\AbstractProduct;
use Magento\Catalog\Model\ProductFactory;

class Upsell extends AbstractProduct
{
    protected $productFactory;
    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
        ProductFactory $productFactory
    ) {
        $this->productFactory = $productFactory;
        parent::__construct($context);
    }

    public function getUpSellProducts()
    {
        $product = $this->_coreRegistry->registry('product');

        $upSellProductIds = $product->getUpSellProductIds();

        if(isset($upSellProductIds)){

            $products = array();

            foreach($upSellProductIds as $productId) {
                $product = $this->productFactory->create()->load($productId);
                $products[] = $product;
            }

            return $products;
        }

        return null;
    }
}