I am working on a Magento 2 module that uses AJAX to download upsell products. Upsell products may vary for each client, which is why AJAX is used to load a block to provide cache overkill.
For this, I have a custom module in which my block extends \Magento\Catalog\Block\Product\ProductList\Upsell . In the modules layout for catalog_product_view.xml , I have the following -
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="product.info.upsell" remove="true" /> <referenceContainer name="content.aside"> <block class="MyCompany\MyModule\Block\Product\ProductList\Upsell" name="personalised.product.upsell" template="MyCompany_MyModule::upsell.phtml" /> </referenceContainer> </body> </page>
In my upsell.phtml -
<div id="personalised-upsells-container" data-role="personalised-upsells"></div> <script type="text/x-magento-init"> { "*": { "MyCompany_MyModule/js/upsell": { "upsellAjaxUrl": "<?php echo $block->getUpsellAjaxUrl(); ?>" } } } </script>
getUpsellAjaxUrl() generates http://magento2.dev/personalised/products/upsellAjax/id/6
My upsell.js is
define([ 'jquery', 'upsellProducts' ], function($) { function getUpsellContent(url) { $.ajax({ url: url, dataType: 'html' }).done(function (data) { $('#personalised-upsells-container').html(data).promise().done(function(){ $('.upsell').upsellProducts(); }); }); } return function (config, element) { getUpsellContent(config.upsellAjaxUrl); }; });
My controller (upsellAjax) -
class UpsellAjax extends ProductController { public function execute() { $productId = (int) $this->getRequest()->getParam('id'); $product = $this->loadProduct($productId); if (!$product) { return false; } $resultLayout = $this->resultFactory->create(ResultFactory::TYPE_LAYOUT); return $resultLayout; } }
My personalised_products_upsellajax.xml -
<?xml version="1.0"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> <container name="root"> <block class="MyCompany\MyModule\Block\Product\ProductList\Upsell" name="product.info.personalised.upsell" template="Magento_Catalog::product/list/items.phtml"> <arguments> <argument name="type" xsi:type="string">upsell</argument> </arguments> </block> </container> </layout>
As expected, this correctly loads the upsell block of the product through ajax, pushes the HTML into my container, and then initializes the upsellProducts widget on the page. My upsell products show as expected, but without price.
I tried a couple of things to debug the situation, but as far as I can see, it cannot load priceRender on line 428 \Magento\Catalog\Block\Product\AbstractProduct inside the getProductPriceHtml() method. String $priceRender = $this->getLayout()->getBlock('product.price.render.default'); always returns false when a block is loaded via AJAX.
This is also the situation when I replace my block with the default block in the layout (personalized_products_upsellajax.xml), for example.
<?xml version="1.0"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> <container name="root"> <block class="Magento\Catalog\Block\Product\ProductList\Upsell" name="product.info.upsell" template="Magento_Catalog::product/list/items.phtml"> <arguments> <argument name="type" xsi:type="string">upsell</argument> </arguments> </block> </container> </layout>
I thought this could have something to do with removing the upsell block first in my layout, i.e. <referenceBlock name="product.info.upsell" remove="true" /> I decided to comment on this line, which results in two upsell blocks, one of which is the default loaded block, and the other is my AJAX block. The same results when the default block shows the correct information, however my AJAX block still lacks prices.
Any help would be greatly appreciated.