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.
Related
I would like all my CMS pages (but not all pages) to use a custom template file, however when I use the setTemplate action in my local.xml file it's not changing the template. The block is rendering correctly but without the correct layout.
The XML I'm using right now is:
<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.1.0">
<cms_page_view>
<reference name="root">
<action method="setTemplate"><template>page/cms-page.phtml</template></action>
</reference>
<reference name="right">
<block type="catalog/navigation" name="default_page_view" template="navigation/game-menu.phtml"/>
</reference>
</cms_page_view>
</layout>
What am I doing wrong?
You aren't doing anything wrong - your directive is being overridden by the entity data. For the reason why, see Mage_Cms_Helper_Page::_renderPage():
protected function _renderPage(/*...*/)
{
//snip...
$action->getLayout()->getUpdate()
->addHandle('default')
->addHandle('cms_page');
$action->addActionLayoutHandles();
if ($page->getRootTemplate()) {
$handle = ($page->getCustomRootTemplate()
&& $page->getCustomRootTemplate() != 'empty'
&& $inRange) ? $page->getCustomRootTemplate() : $page->getRootTemplate();
$action->getLayout()->helper('page/layout')->applyHandle($handle);
}
//snip...
}
So, your directive is being processed under the full action name handle cms_page_view, which is added via the $action->addActionLayoutHandles(); call. Whereas CMS pages are practically always saved via the admin with a root_template value, this value will always override file-based directives.
While it would be possible to update the data, it would be at risk of being overwritten when In order to provide an alternate template which will be preserved when the page is edited via the admin, it's necessary to specify some configuration values and some corresponding layout XML. In your custom module's config XML (or in app/etc/local.xml if this is a non-distributed change):
<global>
<page>
<layouts>
<cms_page_custom>
<label>Empty</label>
<template>page/cms-page.phtml</template>
<layout_handle>cms_page_custom</layout_handle>
</cms_page_custom>
</layouts>
</page>
</global>
This will provide the option to the select input during CMS page administration. To complete this work, in your custom layout XML:
<cms_page_custom>
<reference name="root">
<action method="setTemplate"><template>page/cms-page.phtml</template></action>
<!-- Mark root page block that template is applied -->
<action method="setIsHandle"><applied>1</applied></action>
<action method="setLayoutCode"><name>empty</name></action>
</reference>
</cms_page_custom>
I'm trying to display the cross sell block in it's normal location as well as at the bottom of the page. There is more than one phtml template file involved so $this->getChildHtml does not work in the second location since the block is setup to only be on the cart.phtml file as of now.
In summary, how can I display the same block in more than one template file? I wan't to place these changes in my local.xml and do not want to modify core Magento template files.
The core layout directive for this block is set up as a child of the checkout.cart block:
<checkout_cart_index translate="label">
<!-- ... -->
<reference name="content">
<block type="checkout/cart" name="checkout.cart">
<!-- ... -->
<block type="checkout/cart_crosssell" name="checkout.cart.crosssell" as="crosssell" template="checkout/cart/crosssell.phtml"/>
</block>
</reference>
</checkout_cart_index>
To add it to the footer, you might need to only establish another parent-child relationship in your local.xml:
<checkout_cart_index>
<reference name="footer">
<action method="insert"><!-- or "append" to add to the end -->
<child>checkout.cart.crosssell</child>
</action>
</reference>
</checkout_cart_index>
This approach relies on the stock page/html/footer.phtml template which contains an empty getChildHtml() call, which causes it to render all child blocks.
Note that the footer block class Mage_Page_Block_Html_Footer has a never-expiring block_html cache lifetime, and it does not evaluate child contents for its cache entry. You may need to disable the cache for this block or rewrite the block class to account for the varied content of the crosssell block.
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.
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"/>
Previously in Magento, the wishlist link was added using the following (in wishlist.xml):
<action method="addWishlistLink"></action>
And you could override that and remove it using the following (in your local.xml):
<remove name="wishlist_link"/>
However, in the newest Magento, 1.4.2, they've changed how the wishlist link is added to the following:
<action method="addLinkBlock"><blockName>wishlist_link</blockName></action>
Anyone know how to remove the wishlist link now they’ve changed how it’s added?
It appears there's no publicly available way to reliably remove the wishlist link block from the layout. (you can skip to the end for a workaround)
The addLinkBlock assumes the presence of the block that's been passed, so using remove in the way you describe results in a fatal error being thrown
Fatal error: Call to a member function getPosition() on a non-object in /Users/alanstorm/Sites/magento1point4.2.dev/app/code/core/Mage/Page/Block/Template/Links.php on line 112
Here's the core code that causes that error
app/code/core/Mage/Page/Block/Template/Links.php
public function addLinkBlock($blockName)
{
$block = $this->getLayout()->getBlock($blockName);
$this->_links[$this->_getNewPosition((int)$block->getPosition())] = $block;
return $this;
}
This method assumes its going to be able to pull out a block by whatever name gets passed, so we can't just remove the wishlist_link block as we could in previous versions.
The only mechanism for removing a link appears to be the following method on the same block class
app/code/core/Mage/Page/Block/Template/Links.php
public function removeLinkByUrl($url)
{
foreach ($this->_links as $k => $v) {
if ($v->getUrl() == $url) {
unset($this->_links[$k]);
}
}
return $this;
}
However, this is done using string comparison, and there's no reliable way (that I know of) to generate a URL Object from a layout file, cast it as a string, and pass it into the method (this would be required, as there are numerous configuration settings that can change what the final string URL will be). That makes this method not helpful for our needs.
So, what we can do it modify the existing wishlist_link block to use a blank or non-existant template. This way the block still renders, but it renders as an empty string. The end result is we avoid the fatal error mentioned above, but still manage to remove the link from our selected pages.
The following would remove the link from all the pages using the default handle.
<!-- file: local.xml -->
<layout>
<default>
<reference name="wishlist_link">
<action method="setTemplate"><template>blank-link.phtml</template></action>
</reference>
</default>
</layout>
In your local.xml file,
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="root">
<reference name="top.links">
<!-- Remove wishlist link in magento 1.4.x and newer -->
<remove name="wishlist_link"/>
</reference>
</reference>
</default>
</layout>
You can remove the wishlist link from the admin panel System > Configuration > Wishlist > Enabled = "No"
Add the following to your local.xml file.
<reference name="top.links">
<remove name="wishlist_link"/>
</reference>
This works! I have removed Wishlink from Toplinks and wanted to add it back into another block but that doesn't seem possible when you remove it in this way. Sadly.
I know I'm years late here, but for all of those people who are still looking for answers to this.
I have a way to work around this issue that is only a bit of extra work but it's not hacky and it gives you FULL control of your top.links block.
Simply unset the top.links block and re-create it, it will be empty (no more wishlist_link block) and all you have to do is add whichever links you want inside of it! (Do all of this in your theme/layout/local.xml file of course).
<layout version="0.1.0">
<default>
<!-- HEADER -->
<reference name="header">
<!-- Unsetting the already existing top links block -->
<action method="unsetChild">
<name>topLinks</name>
</action>
<!-- Re-creating a new top links block -->
<block type="page/template_links" name="top.links" as="topLinks">
<!-- EXAMPLE: Account Dashboard Link -->
<action method="addLink" translate="label title" module="catalog">
<label>Account Dashboard</label>
<url helper="customer/getAccountUrl"/>
<title>Account Dashboard</title>
</action>
<!-- You can add any other links that you want -->
</block>
</reference>
</default>
</layout>
Also remember that for some links like Sign In and Log Out you will need to reference your top.links block inside the appropriate <customer_logged_out> and <customer_logged_in> handles instead of inside of <default> as a guide for this you can look at Magento's customer.xml file.
IMPORTANT: If there are any modules included in your project that add links to the top.links block, those links won't show up because local.xml is processed last, so just keep that in mind when using this method :)
I am a Certified Magento Front End Developer with over 3 years of experience and I have overcome LOTS of layout XML headaches to the point where we became best friends.