I'm trying to add custom template to product page under social sharing section. In my module I've following code in layout file default.xml
<body>
<referenceContainer name="product.info.social">
<block class="Magento\Framework\View\Element\Template" name="product.info.custom" template="Lapisbard_Product::social.phtml" after="product.info.addtocart">
</block>
</referenceContainer>
</body>
social.phtml content
<p>Hey there !</p>
<?php //$_product = $block->getProduct();
It is working fine and showing template content on product page. When I'm using block class Magento\Catalog\Block\Product\View instead of Magento\Framework\View\Element\Template so that I can get product object in my template using $block->getProduct();, it's showing a blank page.
1. What mistake I'm doing here?
2. What is the best way to modify product page?
3. Is there a reference layout file which I can use to add new templates to any section of product page writing layout code in my module?
2 Answers 2
The "white page" error comes because Magento\Framework\View\Element\Template have not a getProduct() method.
So I think that the "cleanest" way to do it is create a custom module with a custom block, layout and template (don't worry this just take a few minutes and you have done some parts)
Module Files:
(I will skip /etc/module.xml and registration.php because are trivial, however you could find the complete example here.)
Let start with the Block php file:
Test\Catalog\Block\Product\View\Extra.php
<?php
namespace Test\Catalog\Block\Product\View;
use Magento\Catalog\Block\Product\AbstractProduct;
class Extra extends AbstractProduct
{
}
As you can see it's just a concrete class extending (IMO) the most lightweight Product Abstract Block. You can also extend Magento\Framework\View\Element\Template but in that case you'll need to implement the getProduct() method and change the context in the constructor in order to get access to the registry.
So lets move to the Layout file:
Test/Catalog/view/frontend/layout/catalog_product_view.xml
<?xml version="1.0"?>
<body>
<referenceContainer name="product.info.social">
<block class="Test\Catalog\Block\Product\View\Extra"
name="product.view.extra"
template="Test_Catalog::product/view/extra.phtml"
after="-">
</block>
</referenceContainer>
</body>
And Finally the template file:
Test/Catalog/view/frontend/templates/product/view/extra.phtml
<?php /* @var $block \Test\Catalog\Block\Product\View\Extra */?>
<?php $_product = $block->getProduct() ?>
<h3><?php echo 'My Product Name Is: ' . $_product->getName(); ?></h3>
As you can see is pretty straightforward, simplest than M1-
Remember that all your custom logic should be implemented in the Extra.php block class in order to keep the view clean.
ie:
In the Extra.php class:
public function getSomething()
{
return 'something'
}
in the extra.phtml view:
<?php echo $block->getSomething() ?>
-
2So my module's catalog_product_view.xml layout loads automatically when I'm on product page?amitshree– amitshree2016年01月27日 06:16:57 +00:00Commented Jan 27, 2016 at 6:16
-
2Absolutly! it's very similar to M1 but now every handle is in a separated file.MauroNigrele– MauroNigrele2016年01月27日 06:22:20 +00:00Commented Jan 27, 2016 at 6:22
A Supplement for the Accepted Answer
The accepted answer is good, but the AbstractProduct is deprecated now.
/**
* Class AbstractProduct
* @api
* @deprecated 101.1.0
* @SuppressWarnings(PHPMD.NumberOfChildren)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @since 100.0.2
*/
class AbstractProduct extends \Magento\Framework\View\Element\Template
So, we have to use the Magento\Framework\Registry to achieve the Block, the Block sample is below:
<?php
namespace Vendor\Module\Block;
use Magento\Framework\View\Element\Template;
use Magento\Framework\Registry;
class ProductView extends Template
{
/**
* @var Registry
*/
protected $registry;
/**
* @var \Magento\Catalog\Model\Product
*/
protected $product;
/**
* ProductView constructor.
* @param Template\Context $context
* @param array $data
* @param Registry $registry
*/
public function __construct(
Template\Context $context,
Registry $registry,
array $data = []
)
{
$this->registry = $registry;
parent::__construct($context, $data);
}
/**
* @return \Magento\Catalog\Model\Product
*/
public function getProduct()
{
if ($this->product === null) {
$this->product = $this->registry->registry('product');
}
return $this->product;
}
}
-
Not sure if its really important but PhpStorm (IDE) found 2 warnings: The use of function is_null() is discouraged; use strict comparison "=== null"() instead (in getProduct() method) AND Optional parameter is provided before required (in the constructor move $data at the end).cap340– cap3402020年07月11日 22:44:17 +00:00Commented Jul 11, 2020 at 22:44
-
@urbansurfers You are right. Fix it now. Thank you!Key Shang– Key Shang2020年07月13日 02:30:33 +00:00Commented Jul 13, 2020 at 2:30
$_product = $block->getProduct();when I'm usingMagento\Catalog\Block\Product\Viewblock.