I want to use a block in order to get some data in a template, but it's not working.
Here is my block
class Question extends \Magento\Framework\View\Element\AbstractBlock
{
protected $customerSession;
public function __construct(
Template\Context $context,
\Magento\Customer\Model\Session $customerSession
)
{
$this->customerSession = $customerSession;
parent::__construct($context);
}
public function test()
{
return "OK";
//return $this->customerSession->getCustomer()->getId();
}
}
And this is my catalog_product_view.xml
<?xml version="1.0"?>
<page layout="1column" 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.details">
<block class="Magento\Catalog\Block\Product\View" name="question.tab" as="question" template="Semaine2_TP::product/delivery_info.phtml" group="detailed_info" >
<arguments>
<argument translate="true" name="title" xsi:type="string">Questions</argument>
</arguments>
<block name="question" class="Semaine2\TP\Block\Question" cacheable="false" template="Semaine2_TP::question/info.phtml" group="detailed_info"/>
</block>
</referenceBlock>
</body>
</page>
But with this, only the delivery_info.phtml is printed, and the info.phtml seems to be ignored.
Actually what I would like to be able to do is to use my test function from the block inside my delivery_info.phtml in order to get an action target URL for example or to get the customer if he is logged in.
But when I call $block in my phtml he always seems to search into the Magento\Catalog\Block\Product\View which is normal I guess.
New to magento 2 and no idea how to deal with this. Thanks for your assistance.
The right way is to use Magento View Models instead of Block classes to separate business logic
https://devdocs.magento.com/guides/v2.3/extension-dev-guide/view-models.html
catalog_product_view.xml:
<referenceBlock name="product.info.details">
<block name="question.tab" as="question" template="Semaine2_TP::product/delivery_info.phtml" group="detailed_info" >
<arguments>
<argument translate="true" name="title" xsi:type="string">Questions</argument>
</arguments>
<block name="question" cacheable="false" template="Semaine2_TP::question/info.phtml" group="detailed_info">
<arguments>
<argument name="view_model" xsi:type="object">Semaine2\TP\ViewModel\Question</argument>
</arguments>
</block>
</block>
</referenceBlock>
app/code/Semaine2/TP/ViewModel/Question.php:
<?php
namespace Semaine2\TP\ViewModel;
use Magento\Framework\Registry;
use Magento\Catalog\Model\Product;
use Magento\Framework\View\Element\Block\ArgumentInterface;
/**
* Class Question.
*/
class Question implements ArgumentInterface
{
/**
* #var Registry
*/
private $registry;
/**
* #var Product
*/
private $product;
/**
* #param Registry $registry
*/
public function __construct(
Registry $registry
) {
$this->registry = $registry;
}
/**
* Get current product.
*
* #return Product
*/
public function getProduct(): Product
{
if ($this->product === null) {
$this->product = $this->registry->registry('current_product');
}
return $this->product;
}
}
Are you calling $block->getChildHtml() in your delivery_info.phtml file?
Since you have a custom block and template, I think you need to explicitly call a toHtml for your block. You can also pass in your custom block name to the function, if not I believe all child block HTMLs will be printed.
I was extending the wrong Block.
The block need to extends use Magento\Catalog\Block\Product\View;
Sadly this magento native block is using deprecated arguments, but I think we can't escape from this if we want to be able to call the construct.
Related
I want to display application_no if payment method is FN in order details page.
I have created a block.
class Custom extends \Magento\Framework\View\Element\Template
{
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
array $data = []
) {
parent::__construct($context, $data);
}
}
Also, I have created a sales_order_view.xml to display my application_no (Tested it with static value and working fine).
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="left">
<referenceContainer name="payment_additional_info">
<block class="Limesharp\FinanceNow\Block\Adminhtml\Order\View\Custom" name="sales_order_view_custom" template="order/view/custom.phtml" />
</referenceContainer>
</referenceContainer>
</body>
</page>
Here is my view file -
FN: <?php echo $block->getOrder(); ?>
Now I wanna pass application_no(custom column already in sales_order table) and payment_method. How can I pass this information from block to view of current order and display it conditionally?
I added a second footer block with links by adding the following code to my default.xml in my theme:
(app/design/frontend///Magento_Theme/layout/default.xml)
<referenceContainer name="footer">
<block class="Magento\Framework\View\Element\Html\Links" name="footer_links_custom">
<arguments>
<argument name="css_class" xsi:type="string">footer links</argument>
</arguments>
</block>
</referenceContainer>
<referenceBlock name="footer_links_custom">
<block class="Magento\Framework\View\Element\Html\Link\Current" name="2custom-link">
<arguments>
<argument name="label" xsi:type="string">Custom Links</argument>
<argument name="path" xsi:type="string">page-url</argument>
</arguments>
</block>
</referenceBlock>
What is the easiest way to add a title to the my footer_links_custom block, is there any way to do this in a simple manner? I've tried setting an argument "title" but that didn't work obviously. Is there any way we can know all the attributes there are for a certain block? (css_class, label, path, ...)
Is there no .phtml file for the footer links block?
Magento 2 leaves me behind with a lot of questions...
Thanks for the help!
In /magento/app/design/frontend/theme/theme/Magento_Theme/ You can set up the structure needed for this. and documentation to help can be found at:
http://devdocs.magento.com/guides/v2.0/frontend-dev-guide/bk-frontend-dev-guide.html
In Magento_Theme/layout/default.xml you will find your block declarations, such as what you listed above already.
In Magento_Theme/Block/Html/Footer.php you can set up your controller with your Mage interface, such as...
class Footer extends \Magento\Framework\View\Element\Template implements \Magento\Framework\DataObject\IdentityInterface
{
protected $_copyright;
....
public function getCopyright()
{
if (!$this->_copyright) {
$this->_copyright = $this->_scopeConfig->getValue(
'design/footer/copyright',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
}
return $this->_copyright;
}
...
Magento_Theme/templates/html is where you can put your .phtml that your used to working with in Magento 1. Its not the exact same code obviously, but the idea is still the same here. for example, here is a footer that isn't code but stored in a db:
$om = \Magento\Framework\App\ObjectManager::getInstance();
$manager = $om->get('Magento\Store\Model\StoreManagerInterface');
$store = $manager->getStore(null)->getName();
$connection = $om->create('\Magento\Framework\App\ResourceConnection');
$conn = $connection->getConnection();
$select = $conn->select()
->from(
['o' => 'xyz_sitedata_items'],
['footer']
)
->where('o.storename=?', $store);
$data = $conn->fetchAll($select);
echo $data[0]['footer'];
for the record, using the object manager like this isn't recommended.
for a specific answer to the question posed, i would look to adding code to your footer.php. you can add data in with the construct, as well as reading all the data for the associated block there.
Small part of Page.xml:
<layout version="0.1.0">
....
<default translate="label" module="page">
<label>All Pages</label>
<block type="page/html" name="root" output="toHtml" template="page/2columns-left.phtml">
<block type="page/html_header" name="header" as="header" /> <!-- work -->
<block type="page/html_wrapper" name="u.Top.Menu" as="u_Top_Menu" translate="label"> <!-- doesn't work -->
<label>top menu</label>
<action method="setElementTagName"><value>div</value></action>
<action method="setElementClass"><value>sub-menu</value></action>
</block>
...
</block>
....
And in the 2columns-left.phtml output it:
<?php echo $this->getChildHtml('u_Top_Menu'); ?>
But it always retuns empty value. I'm confused here a bit. What I'm doing wrong here?
This is what happens when you forget to add the children block to the html wrapper block. Look at this block class source code:
class Mage_Page_Block_Html_Wrapper extends Mage_Core_Block_Abstract
{
/**
* Whether block should render its content if there are no children (no)
* #var bool
*/
protected $_dependsOnChildren = true;
/**
* Render the wrapper element html
* Supports different optional parameters, set in data by keys:
* - element_tag_name (div by default)
* - element_id
* - element_class
* - element_other_attributes
*
* Renders all children inside the element.
*
* #return string
*/
protected function _toHtml()
{
$html = empty($this->_children) ? '' : trim($this->getChildHtml('', true, true));
if ($this->_dependsOnChildren && empty($html)) {
return '';
}
...
So far as I can tell you are doing everything correct. The thing that normally trips people up is the as vs name issue whereby a block is referred in xml via it's name, but in templates via it's as. You don't appear to have fallen into this trap, so my best guess is that your cache hasn't been cleaned. An rm -rf var/cache/mage-* should hopefully fix the issue.
Zyava is correct, but I have a workaround!
If you don't want to add children to the block, but still need it to render, there is a class function (dependsOnChildren) that allows you to set this _dependsOnChildren flag from your layout XML like so:
<block type="page/html_wrapper" name="u.Top.Menu" as="u_Top_Menu" translate="label"> <!-- doesn't work -->
<label>top menu</label>
<action method="setElementTagName"><value>div</value></action>
<action method="setElementClass"><value>sub-menu</value></action>
<!-- This will tell PhP to call $blockClass->dependsOnChildren(0); before rendering. -->
<action method="dependsOnChildren"><value>0</value></action>
</block>
Here is that function (for reference)
app/code/core/Mage/Page/Block/Html/Wrapper.php # Line 80
/**
* Setter whether this block depends on children
* #param $depends
* #return Mage_Page_Block_Html_Wrapper
*/
public function dependsOnChildren($depends = '0')
{
$this->_dependsOnChildren = (bool)(int)$depends;
return $this;
}
The main aim is to find where to generate left tag block for new product page. And to modify it.
To get it I'm trying to understand which block is running in case the product is new?
In this code I print out name block.
class Mage_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller_Action
{
//...
/**
* Create new product page
*/
public function newAction()
{
//...
$this->loadLayout(array(
'default',
strtolower($this->getFullActionName()),
'adminhtml_catalog_product_'.$product->getTypeId() . $_additionalLayoutPart
));
// echo adminhtml_catalog_product_new
echo 'adminhtml_catalog_product_'.$product->getTypeId() . $_additionalLayoutPart;
//...
}
//...
}
Find out this block in catalog.xml:
<adminhtml_catalog_product_new>
<update handle="editor"/>
<!-- ... -->
<reference name="left">
<block type="adminhtml/catalog_product_edit_tabs" name="product_tabs"></block>
</reference>
<!-- ... -->
</adminhtml_catalog_product_new>
In the following step I found block model:
class Mage_Adminhtml_Block_Catalog_Category_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { /**
* Initialize Tabs
*
*/
public function __construct()
{
die("debug label");
//....
}
// ...
}
refresh page and ... nothing happaned.
It seems there is not block that we're searching for...which one then?
Firstly, the layout xml says adminhtml/catalog_product_edit_tabs, then it is Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs you should be looking for, not Mage_Adminhtml_Block_Catalog_Category_Tabs.
Secondly, I think it is Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs_Configurable which controls the tabs if you are creating a new configurable product.
I'd like to put some additional info under each item in the cart. I have this info already saved in table "sales_flat_quote_item" in "additional_info" field. So the question is only how to show it globally at all places where the items are shown.
I saw in several places under item name there is a structure like this:
<?php if ($addtInfoBlock = $this->getProductAdditionalInformationBlock()):?>
<?php echo $addtInfoBlock->setItem($_item)->toHtml() ?>
<?php endif;?>
For example in this files:
/app/design/frontend/base/default/template/checkout/cart/item/default.phtml
/app/design/frontend/base/default/template/checkout/onepage/review/item.phtml
So I suppose this is the place I should use for such task.
What I figured out is that:
I have to add my own block definition to for example:
<checkout_cart_index>
<block type="core/text_list" name="additional.product.info" translate="label">
<label>Additional Product Info</label>
<block type="various/itemrendererdefault" name="glass.additional" as="glass" template="checkout/cart/glass_additional.phtml"/>
</block>
</checkout_cart_index>
This is no problem so far. My class is loaded
class Site1_Various_Block_Itemrendererdefault extends Mage_Core_Block_Template {
public function setItem(Varien_Object $item) {
$this->setData('item', $item);
return $this;
}
public function getItem() {
return $this->_getData('item');
}
}
and the template checkout/cart/glass_additional.phtml is called.
But inside the template I have no idea how to get the info about what $item should I process. I tried:
$_item = $this->getItem();
print_r($_item);
$_item = $this->getData();
print_r($_item);
but it returns nothing.
So my question is: How to get $item data inside my template.
Can I access the data set in?
...
$addtInfoBlock->setItem($_item)->toHtml();
...
Krystian, the OP, already self-answered his question.
Quote:
I just solved the issue by setting my block as "additional.product.info"
<checkout_cart_index>
<block type="various/itemrendererdefault" name="additional.product.info" translate="label" template="checkout/cart/glass_additional.phtml"></block>
</checkout_cart_index>
Note: It's absolutely OK to self-answer your own question. Please just post it as an real answer, but not in a question or comment. Posting as real answer helps to keep the "Unanswered" list more clear (avoids making other people wasting their time).
I think to get the item instance you have to try this:
class Site1_Various_Block_Itemrendererdefault extends Mage_Core_Block_Template {
public function setItem(Varien_Object $item) {
$this->setData('item', $item);
return $this;
}
public function getItem() {
$parent = $this->getParentBlock();
if ($parent) {
$item = $parent->getItem();
}
}
}
Thanks !
I was having issues with this as well until I used a block type of core/template and a call to getParentBlock() in my custom template file. This might work for any custom block type but I didn't test.
In your layout/local.xml file:
<checkout_cart_index>
<reference name="additional.product.info">
<block type="core/template" name="additional.product.info.your_template" as="your_template" template="checkout/cart/item/your-template.phtml"/>
</reference>
</checkout_cart_index>
The $addtInfoBlock->setItem($_item)is called on the additional.product.info block, which would be the parent of any blocks you add underneath it. Because of this, you can call $this->getParentBlock() in your template to get access to it's data.
So now, in your checkout/cart/item/your-template.phtml:
$_item = $this->getParentBlock()->getItem();
/* get access to all product attributes, with a performance hit. */
$_product = $_item->getProduct()->load();
/* Some product attributes */
echo $_product->getName();
echo $_product->getSku();