Blocking blocks of different types in Magento
I am trying to change product pages on my Magento installation. In the current theme, product options are displayed in the main body of the page. I am trying to get them to appear in a tab with more details. The problem is the product parameters are being generated by an XML structural block and I can't just move that to a different position, it needs to be translated.
Here's a snippet of XML products:
<block type="catalog/product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="catalog/product/view/options/wrapper.phtml" translate="label">
<label>Info Column Options Wrapper</label>
<block type="core/template" name="options_js" template="catalog/product/view/options/js.phtml"/>
<block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
<action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
<action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
<action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
<action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
</block>
</block>
So there is a block catalog/product_view
in there with a few lines of PHTML appended to it. Good. However, the XML that creates the tabs is asking for something different. Here's a sample:
<block type="catalog/product_view_tabs" name="product.info.tabs" as="info_tabs" template="catalog/product/view/tabs.phtml">
<action method="addTab" translate="title" module="catalog">
<alias>options</alias>
<title>Options</title>
<block>catalog/product_view</block>
<template>catalog/product/view/options/wrapper.phtml</template>
</action>
</block>
There <block>foo/bar_baz</block>
is clearly a different block type in the column than the main blocks here. How can I insert a structural block there? I am trying to get it so that the entire content set generated by the first quoted XML block can be used in a tag <block>
nested inside <action method="addTab">
.
For bonus points, what are the actual names of these two different use cases for <block>
, what is the difference between the content of a tag <block>
and its attributes, and where on this beautiful green earth is any of this documented?
Here is an XML block that ended up working for me, according to Sergey.
<block type="catalog/product_view_tabs" name="product.info.tabs" as="info_tabs" template="catalog/product/view/tabs.phtml" >
<action method="addTab" translate="title" module="catalog">
<alias>product_options_wrapper</alias>
<title>Options</title>
<block>catalog/product_view_description</block>
<template>catalog/product/view/options/wrapper.phtml</template>
</action>
<!-- Inserting an extra block that will generate the content of the Options tab. -->
<block type="catalog/product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="catalog/product/view/options/wrapper.phtml">
<block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
<action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
<action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
<action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
<action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
</block>
</block>
</block>
source to share
Interesting question: I looked at the class Mage_Catalog_Block_Product_View_Tabs
and looked at the function addTab
:
function addTab($alias, $title, $block, $template) {
if (!$title || !$block || !$template) {
return false;
}
$this->_tabs[] = array(
'alias' => $alias,
'title' => $title
);
$this->setChild($alias,
$this->getLayout()->createBlock($block, $alias)->setTemplate($template)
);
}
So you can see that every element passed as an argument is added to the private array _tabs
and also added as a child of the current block. The function does not accept other parameters, which is inconvenient.
Thus, all tabs are displayed in catalog/product/view/tabs.phtml
:
<?php foreach ($this->getTabs() as $_index => $_tab): ?>
<?php if($this->getChildHtml($_tab['alias'])): ?>
This tells us that the tab will only display content assigned to the private array _tabs
and has a child block with a property alias
that matches the value $_tab['alias']
. However, what we can about is to add a tab and then replace in the block content that we want using the standard Magento method to define a block with the same name and override it.
Here's a working example based on your code:
<block type="catalog/product_view_tabs" name="product.info.tabs" as="info_tabs" template="catalog/product/view/tabs.phtml" >
<action method="addTab" translate="title" module="catalog">
<alias>description</alias>
<title>description</title>
<block>catalog/product_view_description</block>
<template>catalog/product/view/description.phtml</template>
</action>
<action method="addTab" translate="title" module="catalog">
<alias>product_options</alias>
<title>test</title>
<block>catalog/product_view_description</block>
<template>catalog/product/view/dummy_example.phtml</template>
</action>
<reference name="product_options">
<action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
<action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
<action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
<action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
</reference>
</block>
This gives us the tabs displayed on the interface, with the options displayed on their tab.
This is how we actually got it:
- We have created a list of blocks
childHtml
with tags<action method="addTab">
. - We created a new block
product.info.options
with the desired content and usedas="product_options"
to give it the same alias as the block the method is looking foraddTab
. - The method
addTab
uses our new block and its template instead of the templatedummy_example.phtml
when it searches for a block with the alias "product_options
", and the net effect is that our block and that block is created a templateoptions.phtml
insteaddummy_example.phtml
.
UPDATE . Replaced block
by creating with the reference
existing one. This solution is now more reliable.
source to share