I'm calling a block from a template as follows. I'm aware it's not the recommended way but the layout.xml approach is giving me trouble
echo $this->getLayout()->createBlock('shoppingbasket/options')
->setTemplate('shoppingbasket/cart/item/default/options.phtml')
->setBlockId('options')
->setProduct($_item->getProduct())
->setSelectedOptions($this->getOptionList())
->toHtml() ?>
The block gets rendered. Now I'm trying to add it via the layout.xml approach
I've added the block to the layout.xml as follows:
<layout>
<checkout_cart_index>
<reference name="checkout.cart">
<block type="shoppingbasket/options" template="shoppingbasket/cart/item/default/options.phtml" name="options"></block>
<action method="addItemRender"><type>simple</type><block>checkout/cart_item_renderer</block><template>shoppingbasket/cart/item/default.phtml</template></action>
</reference>
</checkout_cart_index>
</layout>
and I'm calling the block from the template as follows:
<?php echo $this->getChildHtml('options') ?>
The block isn't appearing and I've tried moving the block everywhere in the layout.xml. What am I doing wrong? Also is there a way to pass parameters to the block using the layout.xml approach as I did with
->setProduct($_item->getProduct())
->setSelectedOptions($this->getOptionList())
Thanks!
you did everything right, except one thing: you should set block alias - "as" attribute of the block.
<block type="shoppingbasket/options" template="shoppingbasket/cart/item/default/options.phtml" name="options" as="options"></block>
Methods getChild or getChildHtml use block alias for retrieving block instance from layout.
Related
I've just started reading up on Magentos (1.9 CE) layout and how it works with the XML and PHTML files.
I've come across the structural blocks and content blocks.
I'm looking at the page.xml file of Magento 1.9 installed RWD package DEFAULT theme.
I've pasted below what i believe is the header, content, and footer from the page.xml file.
My questions
1) Is a block considered to be a content block the moment it is assigned a "template="XXXX.phtml" attribute? EAnd if not, it is known as a structural block?
2) For structural blocks that don't have the template="XXX", how does it ultimately link with the phtml files? My question comes from the context of looking at the header block as seen below, some of its sub blocks have "template" attribute, but none of them seem to point to the header.phtml from "\template\page\html" directory, which i have been editing to customize the look of the Magento site Welcome message.
<block type="page/html_header" name="header" as="header">
<block type="page/template_links" name="top.links" as="topLinks"/>
<block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/>
<block type="core/text_list" name="top.menu" as="topMenu" translate="label">
<label>Navigation Bar</label>
<block type="page/html_topmenu" name="catalog.topnav" template="page/html/topmenu.phtml">
<block type="page/html_topmenu_renderer" name="catalog.topnav.renderer" template="page/html/topmenu/renderer.phtml"/>
</block>
</block>
<block type="page/html_wrapper" name="top.container" as="topContainer" translate="label">
<label>Page Header</label>
<action method="setElementClass"><value>top-container</value></action>
</block>
<block type="page/html_welcome" name="welcome" as="welcome"/>
</block>
<block type="core/text_list" name="content" as="content" translate="label">
<label>Main Content Area</label>
</block>
<block type="page/html_footer" name="footer" as="footer" template="page/html/footer.phtml">
<block type="page/html_wrapper" name="bottom.container" as="bottomContainer" translate="label">
<label>Page Footer</label>
<action method="setElementClass"><value>bottom-container</value></action>
</block>
<block type="page/switch" name="store_switcher" as="store_switcher" after="*" template="page/switch/stores.phtml"/>
<block type="page/template_links" name="footer_links" as="footer_links" template="page/template/links.phtml">
<action method="setTitle"><title>Quick Links</title></action>
</block>
<block type="page/template_links" name="footer_links2" as="footer_links2" template="page/template/links.phtml">
<action method="setTitle"><title>Account</title></action>
</block>
<!-- This static block can be created and populated in admin. The footer_links cms block can be used as a starting point. -->
<!--<block type="cms/block" name="footer_social_links">
<action method="setBlockId"><block_id>footer_social_links</block_id></action>
</block>-->
</block>
There are mainly two types of blocks in Magento
Structural blocks :- These blocks actually defines the structure of a page block. This is where content blocks resides
Example : Header, Left, Right, Footer and Main blocks (defines in page.xml)
Content blocks :- These blocks are actually holding the content. Depends upon the type of block, the content hold by these block varies
Example :- Any custom blocks, core/template block, cms/page block etc.
Normally every content block should come under any of the strucural block that described above. These content block holds different contents depend upon its type. For example, a cms/page block is intend to hold cms page content that we set through admin section. catalog/product_view block is used to hold a product view contents. As you already noted these two content blocks use to hold contents but the content differes from block to block, depending on its type specified. With that said let us look on your problem
1) Structural blocks holds structures of a page. Content block comes under each structual block. So in the above layout code, the block with type page/html_header is a structural block. While all other blocks that come inside this block are content blocks of above structural block. In other words they are children of the header structural block. Now let us look on this header block at backside.
#File : app/code/core/Mage/Page/Block/Html/Header.php
<?php
class Mage_Page_Block_Html_Header extends Mage_Core_Block_Template
{
public function _construct()
{
$this->setTemplate('page/html/header.phtml');
}
......
}
There it is. Our structural block is actually assigned with a template through backend. This means the template that correspond to our header block resides in app/design/frontend/<your_package>/<your_theme>/template/page/html/header.phtml. If you open that file, you can see that the template is actually defining the header portion of our page using html, css and js and invoking its child blocks using a method getChildHtml(). Some portion of above file is shown below.
.....
<div class="quick-access">
<?php echo $this->getChildHtml('topSearch') ?>
<p class="welcome-msg"><?php echo $this->getChildHtml('welcome') ?> <?php echo $this->getAdditionalHtml() ?></p>
<?php echo $this->getChildHtml('topLinks') ?>
<?php echo $this->getChildHtml('store_language') ?>
.....
</div>
.....
As you can see above, it invokes child blocks(in other words content blocks) that are defined in page.xml layout file, using getChildHtml() method.
This means, if you add a custom child block inside the header structural block and didn't invoke it in header.phtml using getChildHtml() method, your content block is not going to show in frontend.
You can also set header.phtml to the block header through page.xml like this
<block type="page/html_header" name="header" as="header" template="page/html/header.phtml" />
There is no issue with this. So in short, we cannot generally say that a block that defines a phtml file is either a content block or a strutural block. How both of these block defferes purely depends on what those block holds.
Short Note : A cotent block can contain other content blocks. What we are doing is most of the time is this. Means adding our custom content block to another content block that already existing in magento.
2) If you look on different blocks in magento, you can see that, irrespective of structural block/content block, a block can set with a template through layout or through backend. We can set template to a block using an observer also. I already stated how header structural block set with the template header.phtml
. In this case it is through backend side.
Hopes that helps you to understand the concept.
EDIT
No you are absoulutely wrong. In magento layout holds the entire structure of a page. It holds all the blocks that need to render for a particular page.
Suppose you have a url www.mydomain.com/index.php/customer/account. What magento does now is it will split the url and find which module generates such url. So here above url split like this
base url => www.mydomain.com/index.php/
frontend name => customer/
action controller name => account/
method => index/
Now magento will query for which module that is responsible for frontend name customer. It is defined by Mage_Customer core module. Now magento look for which controller that handles this url. In our url, the part that mention this is account. So it will look for AccountController.php file in Mage_Customer module. Now again magento look for whcih method that handles the url. But in our url there is no method specified. So it will assume the method index hence. Now look on that method.
#File:app/code/core/Mage/Customer/controllers/AccountController.php
/**
* Default customer account page
*/
public function indexAction()
{
$this->loadLayout();
// some other codes
$this->renderLayout();
}
This is the important section. First the method calls a function loadLayout(). This simple code does a lot of work behind the curton. It will generate a big layout tree that is correspond to the page that is going to show in frontend. Where is this layouts are defined ? Of course.. It is in layout XML files. Layout xml file defines what are the blocks that should render for this above url and what are not. For an example in this context, follwing handles will be processed by magento.
default
STORE_default
THEME_frontend_default_default
customer_account_index
customer_logged_in
customer_account
Magento will generate a huge layout tree that will consist of all blocks that is specified under these layout handles. Layout handles may come in any layout XML file that comes under the directory app/design/frontend/<your_package>/<your_theme>/layout. After creating this layout tree, magento will render these layout tree using the code renderLayout(). Basically what it will do is convert these layout into html and render it (For this it uses template files and skin).
Now what would you think ? Layout XMLs are that simple? :)
Trying to add a new cart block to the header within local.xml this is what i have
<default>
<reference name="header">
<block type="checkout/cart_sidebar" name="cart_topbar" as="topCart" template="checkout/cart/top-cart.phtml"/>
</reference>
</default>
Then with in the header i call it with <?php echo $this->getChildHtml('topCart')?> however it shows nothing.
If i try changing the type to type="core/template" then the template will show the content. So this leads me to think i'm missing something specific to the checkout/cart_sidebar type?
The top-cart.phtml file simple contains a single text line to eliminate anything within that.
that's is your local.xml?
syntax is correct.
have you modify any thing else in Mage/Checkout/Block/Cart/Sidebar.php?
I have an index controller with a view action that does the following:
echo $this->getLayout()
->createBlock('core/template','builder')
->setTemplate('pages/builder/view.phtml')
->setHeaderText($extra->getHeaderText())
->setFooterText($extra->getFooterText())
->setProducts($collection)
->toHtml();
Based on this, I am trying to perform layout updates in builder.xml (which is being set in the module's config.xml). However, I am not sure if you can target blocks instantiated in this manner. Based on the above block creation, am I able to perform the following:
<layout version="0.1.0">
<builder_index_view>
<!-- shouldn't this reference the createBlock() name argument? -->
<reference name="builder">
<block type="page/html_header" name="builder.header" as="builder.header" template="pages/builder/header.phtml"/>
</reference>
</builder_index_view>
</layout>
If the block is instantiated prior to the call to loadlayout(), yes.
I'm trying to reference a block from an other custom module to add a child block via layout file but it does not work.
The first layout file contains
<catalog_product_view>
<reference name="content">
<block type="core/template" name="tabcontainer" as="tabcontainer"
template="store/tabcontainer.phtml" >
<block type="catalog/product_list_related" name="kitparts"
template="store/product/kitparts.phtml"/>
</block>
</reference>
</catalog_product_view>
and in the second one I try to reference the tabcontainer block
<catalog_product_view>
<reference name="tabcontainer">
<block type="productshippinginfo/productshipping" name="productshippinginfo"
template="productshippinginfo/productshipping.phtml" after="kitparts"/>
</reference>
</catalog_product_view>
but the productshippinginfo block is not displayed while it is definitely included in the layout (using Alan Storm's layoutviewer plugin). If I reference content it is displayed.
What is wrong? Isn't it possible to add a child to a custom block from a custom extension?
Thanks for your help!
(I'm using Magento 1.6.1.0)
[edit]
in tabcontainer.phtml I'm calling <?php echo $this->getChildHtml(); ?>
First of all: Thank you Vinai!
Adding a dependency to control the loading order of my plugins it works!
in File: app/etc/modules/Company_ContentModule.xml
<Company_ContentModule>
<active>true</active>
<codePool>local</codePool>
<depends>
<Company_ContainerModule />
</depends>
</Company_ContentModule>
So the content module is loaded after the container module.
You are close. You just need to add this to you store/tabcontainer.phtml file:
getChildHtml('productshippinginfo'); ?>
The reason blocks that are children of "content" render without a template change is that the "content" block is a core/text_list block. If you look in Mage_Core_Block_Text_List, you will see that in its rendering method (_toHtml()) it renders its children.
You could also add an empty getChildHtml() call to your tabcontainer template to achieve a similar effect as a core/text_list - in fact, if you use getChildHtml('',false,true); you'll get the sorted children (set with before="" and after="" params).
EDIT: adjusted the getChildHtml() call syntax based on OP's comment correct findings that the first param must be an empty string a/o/t a boolean.
In the second layout I think you need to provide the nesting:
<catalog_product_view>
<reference name="content">
<reference name="tabcontainer">
<block type="productshippinginfo/productshipping" name="productshippinginfo"
template="productshippinginfo/productshipping.phtml" after="kitparts"/>
</reference>
</reference>
</catalog_product_view>
In order that maganto picks that up
And because you are doing
<?php echo $this->getChildHtml(); ?>
You do not need to specifically call it by name unless you want it to appear in a particular place in your HTML output.
In order to test if your block is appearing in the page at all add output="toHtml" in you block tag.
<block type="productshippinginfo/productshipping" name="productshippinginfo"
template="productshippinginfo/productshipping.phtml" after="kitparts" output="toHtml"/>
I am trying to customize a theme using only local.xml whenever possible. I want to add a static block to the header without modifying header.phtml. This code works fine for the content area, but not for the header:
<default>
<reference name="content">
<block type="cms/block" name="how-it-works-button">
<action method="setBlockId"><block_id>how-it-works</block_id></action>
</block>
</reference>
</default>
Anybody know why? I thought that all I would need is to change “content” to “header”, but nothing shows up when I do.
Thanks for your help!
The content block is a special block known as a core/text_list block (PHP class Mage_Core_Block_Text_List). These blocks will automatically render out any child blocks that are added to them.
The header block, on the other hand, is a page/html_header block (PHP class Mage_Page_Block_Html_Header). This block class inherits from Mage_Core_Block_Template, making it a core/template block. Template blocks will only render sub-blocks if their corresponding phtml template requests the block. So, by adding your block to the header, you're only doing half the work you need to. You'll need to create a custom phtml template.
The simplest way to do this (post 1.4.1.1 is to, in your own theme, create a file at
template/page/html/header.phtml
And then at the end of this file add
<?php echo $this->getChildHtml('how-it-works-button'); ?>
Assuming you've added a block to header block via layout xml, this should render your template.
Please Try this
<?php echo $this->getLayout()->createBlock('cms/block')->setBlockId('how-it-works')->toHtml() ?>
And this code in header.phtml
add output="toHtml" in the block tag. I think it is only that.