Magento: Using custom variables in a layout file - magento

Is it possible to use Custom Variables in a layout file? I can use them in a template file like this:
Mage::getModel('core/variable')->loadByCode('variableCode')->getData('store_plain_value')
But not sure with the xml file.
I know I could use the above instead, but this would be useful to know anyway for future uses too.
UPDATE: Have been most unclear I'm afraid. I am specifically looking to access the admin panel "Custom Variables" section, not just pass my own variables to a block. I do apologise for the lack of clarity.

Mage_Core_Block_Abstract extends Varien_Object and inherits its __call() overloading. Whereas block actions in layout XML call block methods, the following are possible:
Pass a string (and it can be translated!):
<action method="setSomeVal" translate="arg" module="some/helper">
<arg>Some String</arg>
</action>
Pass an array:
<action method="setSomeVal">
<arg>
<key1>Some String</key1>
<key2>Some String</key2>
<key3>
<multikey1>Some String</multikey1>
</key3>
</arg>
</action>
Pass anything you want:
<action method="setSomeVal">
<arg helper="some/helper/method">
<param_for_the_helper_method>
<getting_crazy>Oh Boy.</getting_crazy>
</param_for_the_helper_method>
</action>
Retrieve the value in the block/template with $this->getSomeVal();.
Fun, huh?

Did you try the following :
<!-- in layout xml file -->
<action method="setData"><name>color_id</name><value>5</value></action>
Then, you can use in block file like below :
$colors = $this->getColorId();
# or
$colors = $this->getData('color_id');

Based on the updated question:
Create a helper class which wraps the core/variable functionality, e.g:
class Some_Module_Helper_Variable
{
public function getVariableData($code,$param)
{
return Mage::getModel('core/variable')->loadByCode($code)->getData($param);
}
}
Then, in layout XML for your block you can do this (I believe):
<action method="setSomeVal">
<arg helper="class_group/variable/getVariableData">
<arg1>variableCode</arg1>
<arg2>store_plain_value</arg2>
</arg>
</action>

Related

Adding title to cms footer block

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.

Set template for block if there are blocks with the same name

I'm trying to change template for 'form' block in such layout:
<adminhtml_sales_order_create_index>
...
<reference name="root">
<block type="adminhtml/sales_order_create" name="content">
<block type="adminhtml/sales_order_create_form" template="sales/order/create/form.phtml" name="form">
...
<block type="adminhtml/sales_order_create_shipping_method" template="sales/order/create/abstract.phtml" name="shipping_method">
<block type="adminhtml/sales_order_create_shipping_method_form" template="sales/order/create/shipping/method/form.phtml" name="form" />
</block>
<block type="adminhtml/sales_order_create_billing_method" template="sales/order/create/abstract.phtml" name="billing_method">
<block type="adminhtml/sales_order_create_billing_method_form" template="sales/order/create/billing/method/form.phtml" name="form" />
</block>
<block type="adminhtml/sales_order_create_newsletter" template="sales/order/create/abstract.phtml" name="newsletter">
<block type="adminhtml/sales_order_create_newsletter_form" template="sales/order/create/newsletter/form.phtml" name="form" />
</block>
...
I do
<adminhtml_sales_order_create_index>
<reference name="form">
<action method="setTemplate">
<template>my_module/sales/order/create/form.phtml</template>
</action>
</reference>
</adminhtml_sales_order_create_index>
But this does not work. I think because block with name form exist in several places more after. I just want to change it in block type="adminhtml/sales_order_create_form". How can I do this?
#input
Rewrite of block is not the best appoach. It is better to observe 'core_block_abstract_to_html_before' event and change template there I think. Like:
if ($observer->getBlock() instanceof Mage_Adminhtml_Block_Sales_Order_Create_Form) {
$observer->getBlock()->setTemplate('my_module/newtemplate.phtml');
}
This works and is better because you will not get modules conflict if somebody else will rewrite this block. But I thought that may be possible on layout level..
Whilst not the prettiest solution I too do not know of a way of setting a template on a non unique form reference.
Warning this is pretty gross, and I am really not sure of the side affects and for some reason calling setTemplate in the constructor is not enough I guess this is being called at a earlier or later stage than the parents
class My_Module_Block_Adminhtml_Sales_Order_Create_Form extends Mage_Adminhtml_Block_Sales_Order_Create_Form
{
public function _toHtml()
{
$this->setTemplate('my_module/sales/order/create/form.phtml');
return parent::_toHtml();
}
}
Add the write to your Module
<blocks>
<adminhtml>
<rewrite>
<sales_order_create_form>My_Module_Block_Adminhtml_Sales_Order_Create_Form</sales_order_create_form>
</rewrite>
</adminhtml>
</blocks>
I really hope there is a better solution than this.
your right, thats the reason why its not working.
i can't think of a clean way because of this bad naming.
However there are several options that are not clean but will work:
1 option: copy the whole sales.xml into your own admin layout folder and change the template there directly.
2 option: "rewriting" "Mage_Adminhtml_Block_Sales_Order_Create_Form" and set the template from the code
3 option: subscribe to "adminhtml_block_html_before" and listen for the right block and change the template then.
However if you write a community module non of these options are really good.
if it is your own project i would go for option 1
hope that helps
For overwriting the form name form.phtml file from the billing_method you should do the following:
In the config.xml:
<core_block_abstract_to_html_before>
<observers>
<mymodule_core_block_abstract_to_html_before>
<class>MyModule_Model_MyPath</class>
<method>setTemplateFile</method>
</mymodule_core_block_abstract_to_html_before>
</observers>
</core_block_abstract_to_html_before>
and in your observer:
public function setTemplateFile(Varien_Event_Observer $observer)
{
if ($observer->getBlock() instanceof Mage_Adminhtml_Block_Sales_Order_Create_Billing_Method_Form) {
$observer->getBlock()->setTemplate('mymodule/sales/order/create/billing/method/form.phtml');
}
}

Magento - Is it possible to specify multiple values for ifconfig?

I want to specify multiple values for ifconfig in layout xml.
<action method="setTemplate" ifconfig="mymodule/general/is_enabled">
<template>mymodule/test.phtml</template>
</action>
Is is possible to add below two conditions for one action?
ifconfig="mymodule/general/is_enabled"
ifconfig="mymodule/frontend/can_show"
Any suggestions would be most welcome.
You could use a helper method in your action parameter. Something like this
<action method="setTemplate">
<template helper="mymodule/myhelper/canShowIf"/>
</action>
will call setTemplate with the results of a call to
Mage::helper('mymodule/myhelper')->canShowIf();
And the following in your modules default helper:
public function canShowIf()
{
if($displayOnly = Mage::getStoreConfig('mymodule/general/is_enabled') == true)
// Do Something
}else if($displayOnly = Mage::getStoreConfig('mymodule/frontend/can_show') == true) {
// Do Something Else
}
return $displayOnly;
}
Implement your custom logic in canShowIf.
Define a function in Helper (Data.php)
<reference name="root">
<action method="setTemplate">
<template helper="modulename/getNewLayoutupdate"/>
</action>
</reference>
in helper function you can load template by conditions.
consider below scenario:
<catalog_category_default>
<reference name="product_list">
<action method="setTemplate" >
<template>mymodule/mytemplate.phtml</template>
</action>
</reference>
</catalog_category_default>
ifconfig : If return value is false, then it takes layout defined in base folder.
helper function : If return value is false, then does not take layout defined in base folder, and not template gets added. that's why empty block is shown.
ifconfig="mymodule/general/is_enabled"
ifconfig="mymodule/frontend/can_show"
why not create an additional config node
ifconfig="mymodule/frontend/is_enabled_can_show" and depending on this value proceed.

Magento - move block from right to left

Not sure why this is so difficult. If I understand THIS correctly, I should be able to swiftly accomplish my goals... But no joy.
So - I'm building my first theme, and still getting my head around layout...
I'm working specifically on the Catalog Product View page, and am converting this page from a right column layout to a left column layout. I simply want to move the blocks from the right into the left.
In the default catalog.xml, product_list_related is defined:
</catalog_product_view>
//...
<reference name="right">
<block type="catalog/product_list_related" name="catalog.product.related" before="-" template="catalog/product/list/related.phtml"/>
</reference>
</catalog_product_view>
In my local.xml, I'm simply trying to move this block:
<layout>
// bunch other page directives
<catalog_product_view>
<reference name="root">
<action method="setTemplate"><template>page/2columns-left.phtml</template></action>
</reference>
<reference name="right">
<action method="unsetChild"><name>catalog.product.related</name></action>
</reference>
<reference name="left">
<action method="insert"><blockName>catalog.product.related</blockName></action>
// note that that "catalog.leftnav" gets inserted as expected
<block type="catalog/layer_view" name="catalog.leftnav" after="-" template="catalog/layer/view.phtml"/>
</reference>
</catalog_product_view>
</layout>
As noted - inserting catalog.leftnav works as expected, so I'm assuming everything else is set up correctly. The target block renders as expected if I leave the template and other directives unchanged, which tells me that the block should render once its been properly unset and inserted...
This is driving me nuts... but what else is new with Magento.
Cheers -
b[]x
UPDATE
Because I simply can not get a local.xml override to work, I'm just falling back on a modified catalog.xml. I'm a reasonably smart guy... it worries me that I can't get this to work (and that magento just silently fails, whatever the case ) - but I can't waste anymore time dicking around with this stupid issue.
Moving on.
UPDATE, again.
Spent some time, now, working in magento and getting more familiar with its complexities. I came back to this issue today as I need to get my local.xml working right.
I really don't know what I had wrong, but this set of directives finally worked.
<reference name="right">
<action method="unsetChild">
<alias>catalog.product.related</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
</action>
</reference>
A key point I'll make note of for others dealing with this:
Layout xml directives call available methods within magento classes. In this case, Page.xmls "Left" block is of type Mage_Core_Block_Text, which inherits from Mage_Core_Block_Abstract which contains the methods unsetChild and insert.
from Mage_Core_Block_Abstract :
/**
* Unset child block
*
* #param string $alias
* #return Mage_Core_Block_Abstract
*/
public function unsetChild($alias)
{
if (isset($this->_children[$alias])) {
unset($this->_children[$alias]);
}
if (!empty($this->_sortedChildren)) {
$key = array_search($alias, $this->_sortedChildren);
if ($key !== false) {
unset($this->_sortedChildren[$key]);
}
}
return $this;
}
and
/**
* Insert child block
*
* #param Mage_Core_Block_Abstract|string $block
* #param string $siblingName
* #param boolean $after
* #param string $alias
* #return object $this
*/
public function insert($block, $siblingName = '', $after = false, $alias = '')
{
if (is_string($block)) {
$block = $this->getLayout()->getBlock($block);
}
if (!$block) {
/*
* if we don't have block - don't throw exception because
* block can simply removed using layout method remove
*/
//Mage::throwException(Mage::helper('core')->__('Invalid block name to set child %s: %s', $alias, $block));
return $this;
}
if ($block->getIsAnonymous()) {
$this->setChild('', $block);
$name = $block->getNameInLayout();
} elseif ('' != $alias) {
$this->setChild($alias, $block);
$name = $block->getNameInLayout();
} else {
$name = $block->getNameInLayout();
$this->setChild($name, $block);
}
if ($siblingName === '') {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
} else {
$key = array_search($siblingName, $this->_sortedChildren);
if (false !== $key) {
if ($after) {
$key++;
}
array_splice($this->_sortedChildren, $key, 0, $name);
} else {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
}
$this->_sortInstructions[$name] = array($siblingName, (bool)$after, false !== $key);
}
return $this;
}
Local xml parameters are important, then, not in name (specifically), but in order ie:
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
<siblingName>catalog.leftnav</siblingName>
<after>1</after>
<alias>catalog_product_related</alias>
</action>
</reference>
Ultimately, this makes local.xml a really powerful method of manipulating the system, but if you are unfamiliar with it and the magento system, get ready for weeks or months of work to really get your head around it.
Cheers
Yet another update
I've run into the problem several times now, where a block I want to move has been removed. This is a problem, as any block that has been removed from layout is nuked forever.
However, with Alan Storm's very handy Unremove Plugin you can undo whats been done:
<checkout_onepage_index>
<x-unremove name="left" />
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
</checkout_onepage_index>
It manages this feat by watching the layout object, and building a list of removed blocks, which can be later referenced.
Nice!
This is a dusty thread now, but for the record, this is the final answer I went with.
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
Magento recommends including this in your local.xml, and it has proved an effective technique.
An alternative approach is to rename the "right" block to "left" rather than move blocks from right to left. However, this will not work if the "right" block is being removed in the first place as I suggested might be the case in my other answer.
<remove name="left" />
<reference name="right">
<action method="setNameInLayout"><name>left</name></action>
</reference>
<reference name="root">
<action method="setChild"><alias>left</alias><name>left</name></action>
<action method="unsetChild"><alias>right</alias></action>
</reference>
<!-- make sure nothing referencing "right" comes after this! -->
If you are just looking to change the output from 2col-right, to 2col-left, it would have been much, much easier to just change
<reference name="right" ...
to
<reference name="left" ...
There is no need to unset or insert any children or re-declare anything. You are overcomplicating things and duplicating code needlessly.
If you are making your own very besoke design too, I would suggest starting copying the entire ./app/design/frontend/base directory to ./app/design/frontend/mypackage - then work from the mypackage/default directory to re-skin your site. Its cleaner and easier. Others may comment on the potential issues of upgrade-ability if you copy every file (rather than just the ones you intend to modify), but it is by far a better practice and much less prone to errors, difficulties and general maintenance.
Edit: To follow up on this in more detail - have a look https://magento.stackexchange.com/a/3794/361
The "right" block is probably being removed with a <remove name="right" /> at some point in the layout. If so, this will cause the "catalog.product.related" block to never be added to the layout in the first place so there is no block to insert into the "left" block.
I'm pretty sure this is the issue, but to confirm, add a Mage::log("Removed $blockName"); in Mage_Core_Model_Layout->generateXml() inside the for loop and check the log after loading the page.
If I'm right, simply copy the <block..> into your local.xml and remove the "unsetChild" and "insert" actions.
I would do it this way: In your local.xml under e.g.
<reference name="right"></reference>
you remove the blocks, e.g.:
<remove name="right.poll">
and then you add the blocks in
<reference name="left"></reference>
Copying base/default to a local theme is a horrible idea. Every update to a core theme file on a Magento version upgrade leads to the same vulnerability of modifying app/code/core files -- needing you to diff the files out on upgrades.
Your proper course of action is modifying a single local.xml with your additions or overrides. If that doesn't suffice, use the proper syntax to create a module in app/code/community with your layout definitions and custom layout XML files.
I think the best answer to modify Magento layouts is given on Classyllama.com
http://www.classyllama.com/development/magento-development/the-better-way-to-modify-magento-layout
When you use the remove tag, it removes any blocks with the specified name from the entire layout, regardless of the context. So, if I remove right.newsletter in the context and that name is used in say the context, then both blocks will be removed. Because remove operates on the global context, you can only remove an element once. Since is being called in catalogsearch.xml, we have to unset it, or else we'll get an error.
<action method="unsetChild"><name>right.newsletter</name></action>;

Add a link to Magento's My Account Page Conditionally

I would like to create a link on the My Account page that only get displays under certain conditions.
Right now I have the link display all the time by adding the following entry to my layout XML file:
<customer_account>
<reference name="customer_account_navigation">
<action method="addLink" translate="label" module="nie"><name>nie</name><path>nie</path><label>NIE Admin</label></action>
</reference>
</customer_account>
I am assuming there is a way to code this so that it only displays under certain circumstances.
The cart & checkout links already do something similar so their method can be copied.
Create a block. It won't be displaying directly so can be descended from the boring Mage_Core_Block_Abstract.
Give it a method where the conditional logic will go.
public function addNieLink()
{
if (($parentBlock = $this->getParentBlock()) && (CONDITION-GOES-HERE)) {
$parentBlock->addLink($this->_('NIE Admin'), 'nie', $this->_('NIE Admin'), true, array(), 50, null, 'class="top-link-cart"');
// see Mage_Page_Block_Template_Links::addLink()
}
}
protected function _prepareLayout()
{
// Add the special link automatically
$this->addNieLink();
return parent::_prepareLayout();
}
Put your check in place of CONDITION-GOES-HERE.
Add your block to the links block.
<customer_account>
<reference name="customer_account_navigation">
<block type="yourmodule/link" name="yourmodule.link" />
</reference>
</customer_account>
(Correct the block type here to your newly created link block)
The important bit is it calls getParentBlock() to find out where the link is to go.

Resources