2

I have been trying to get crosssell products to show on the product pages. however adding the block does not work as it relies on the product being in the cart. I have tried to overcome this by following the following post: Magento 2 - How To Display Cross Sell Products On Product Details Page (PDP)?

The module described here no longer seems to work however as folowing error occurs:

"PHP Fatal error: Uncaught Error: Call to a member function toHtml() on null "

Removing the toHtml function allows my page to load and a list of products is almost rendered however some data for products does not seem to be available.

This is the code i'm currently using for my block:

<?php
namespace Vendor\Module\Block;

class Crosssellproduct extends \Magento\Catalog\Block\Product\AbstractProduct implements \Magento\Framework\DataObject\IdentityInterface {

protected $_registry;
protected $_itemCollection;

public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    \Magento\Framework\Registry $registry, 
    array $data = []
) {
    $this->_registry = $registry;
    parent::__construct(
        $context,
        $data
    );
}

public function getCurrentProduct() {
    return $this->_registry->registry('current_product');
}

public function getItems() {
    $items = $this->getData('items');
    if ($items === null) {
        $product = $this->getCurrentProduct();
        $items = $product->getCrossSellProducts();
        $this->setData('items', $items);
    }
    return $items;
}

public function getItemCount() {
    return count($this->getItems());
}

public function getIdentities()
{
    $identities = [];
    foreach ($this->getItems() as $item) {
        $identities = array_merge($identities, $item->getIdentities());
    }
    return $identities;
}
}

UPDATE

Using some code from related products i have it a little closer to working with working links and add to cart buttons. I've updated code in question to above. However images show the placeholder image, names are not showing and prices appear as £0.00. So below sections of code do not appear to work as expected:

echo $block->escapeHtml($_item->getName())
echo $block->getProductPrice($_item);
echo $block->getImage($_item, $image)->toHtml();

However these do work:

echo $block->getProductUrl($_item)
$block->getAddToCartUrl($_item)

Does anyone know why these would be failing slightly and what is required to allow these to work?

  • Cross Sell products are designed to be displayed on shopping cart page, why do you want it to use on Product pages? Related and Upsell products are already available. – Dexter Jun 30 '17 at 10:42
  • I know it's just crosssell have already been set up so rather than additional time spent adding all crosssell products to upsell to hundreds of products i thought this would be a quicker option. I'm open to other ideas for this however would rather do it with code than additional time in maintaining the store. – harri Jun 30 '17 at 10:51
2

Ok i've sussed it for if anyone needs to do this in future:

<?php
namespace Vendor\Module\Block;

class Crosssellproduct extends \Magento\Catalog\Block\Product\AbstractProduct implements \Magento\Framework\DataObject\IdentityInterface {
protected $_itemCollection;
public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    array $data = []
) {
    $this->_registry = $context->getRegistry();
    parent::__construct(
        $context,
        $data
    );
}

protected function _prepareData()
{
    $product = $this->_registry->registry('current_product');
    $this->_itemCollection = $product->getCrossSellProductCollection()->addAttributeToSelect(
        $this->_catalogConfig->getProductAttributes()
    )->setPositionOrder()->addStoreFilter();
    $this->_itemCollection->load();
    foreach ($this->_itemCollection as $product) {
        $product->setDoNotUseCategoryId(true);
    }
    return $this;
}

protected function _beforeToHtml()
{
    $this->_prepareData();
    return parent::_beforeToHtml();
}

public function getItems()
{
    return $this->_itemCollection;
}

public function getItemCount() {
    return count($this->getItems());
}
public function getIdentities()
{
    $identities = [];
    foreach ($this->getItems() as $item) {
        $identities = array_merge($identities, $item->getIdentities());
    }
    return $identities;
}
}

And then this block within your module can then be referenced like so:

         <block class="Vendor\Module\Crosssellproduct" name="product.crosssell" template="Magento_Catalog::product/list/items.phtml" after="-">
            <arguments>
                <argument name="type" xsi:type="string">crosssell</argument>
            </arguments>
            <block class="Magento\Catalog\Block\Product\ProductList\Item\Container" name="crosssell.product.addto" as="addto">
                <block class="Magento\Catalog\Block\Product\ProductList\Item\AddTo\Compare"
                       name="crosssell.product.addto.compare" as="compare"
                       template="Magento_Catalog::product/list/addto/compare.phtml"/>
            </block>
        </block> 

I would like to modify it so that it includes standard crosssell plus the crosssell products for the products being viewed however this answers the question.

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.