Load Additional Product Attributes in Wishlist

collection;magento-2.1magento2productwishlist

I want to show some additional product attributes in the wishlist template, but they are not loaded. On the category page it is working, so it is not an index problem.

When I call

$item->getProduct()

I see that the product has already been loaded, but not with all attributes, so obviously it is coming from a collection.

The wishlist items are coming from Magento\Wishlist\Block\Customer\Wishlist::getWishlistItems() and are passed around in the templates. But where are the products loaded and how can I specify which attributes I need?

I can force a reload, and it would work:

$item->getProduct()->load($item->getProduct()->getId()))

But obviously this is not the right way.

Best Answer

Where are the products loaded?

The products are loaded in the "_afterLoad" method of the items collection. A product collection is instantiated there based on the product ids of all items and directly loaded to assign the products to their wishlist items.

Unfortunately it is instantiated and loaded from within the same method, so it is not easily changed via plugin. The attributes to select are hard coded:

    $attributesToSelect = [
        'name',
        'visibility',
        'small_image',
        'thumbnail',
        'links_purchased_separately',
        'links_title',
    ];

The method dispatches an event wishlist_item_collection_products_after_load, but unfortunately no "before load" event.

How can you specify the loaded attributes then?

You could replace the collection class, or write a plugin for the _assignProducts method that replaces the whole method.

But I found a better way: use a custom product collection factory that sets the attributes to select during creation.

These files go into a custom module Stack_Wishlist:

etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="\Magento\Wishlist\Model\ResourceModel\Item\Collection">
        <arguments>
            <argument name="productCollectionFactory" xsi:type="object">\Stack\Wishlist\ResourceModel\ProductCollectionFactory</argument>
        </arguments>
    </type>
</config>

ResourceModel/ProductCollectionFactory.php

<?php

namespace Stack\Wishlist\ResourceModel;

use Magento\Catalog\Model\Config as CatalogConfig;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
use Magento\Framework\ObjectManagerInterface;

class ProductCollectionFactory extends \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
{
    /**
     * @var CatalogConfig
     */
    protected $catalogConfig;

    public function __construct(ObjectManagerInterface $objectManager, CatalogConfig $catalogConfig, $instanceName = ProductCollection::class)
    {
        parent::__construct($objectManager, $instanceName);
        $this->catalogConfig = $catalogConfig;
    }

    public function create(array $data = array())
    {
        $collection = parent::create($data);
        $collection->addAttributeToSelect($this->catalogConfig->getProductAttributes());
        return $collection;
    }
}

Here I add all attributes that are configured as "used in product listing", i.e. all that are present in the flat index tables. You could specify them manually instead as well.

Related Topic