I am working on a custom module which takes product images from external server. I have overridden a few functions to get the required result.
But I have to override base/default/template/catalog/product/view/media.phtml inside my custom module.
I tried to do this from default/layout/MY_MODULE.xml but that did not work for me.
How do I override the media.phtml inside default/MY_MODULE.
I think calling setTemplate method is not the right way to override template file in your case. For me it looks a bit redundant and unclear: you are assigning template to block and the immediately reassign it with action. I would do this way:
<catalog_product_view>
<reference name="product.info">
<block type="catalog/product_view_media" name="product.info.media" as="media" template="MY-MODULE/catalog/product/view/media.phtml" />
</reference>
</catalog_product_view>
I think you could also reference to product.info.media directly and call setTemplate action there
Related
I am trying to change checkout/cart.phtml through layout update in my module's layout file i.e. mymodule.xml
<layout>
<checkout_cart_index>
<reference name="checkout.cart">
<action method="setCartTemplate"><value>mymodule/checkout/cart.phtml</value></action>
</reference>
</checkout_cart_index>
</layout>
But It is not working. Any clues?
Ankita, What I'm about to write is the actual way to get what you want. While the official answer by John Hickling will work, it is not how Magento intended the main cart template to be modified.
Magento deliberately chose to use different methods for setting the cart templates, namely, setCartTemplate and setEmptyTemplate. They can be seen in Magento's own app/design/frontend/base/default/layout/checkout.xml. This was done so that two templates can be managed, each to handle their own condition. The first condition is for a cart with items, while the second condition is for a cart without items. By using the common setTemplate method, that distinction will be lost: a cart with items and a cart without items will both display the same template. This is no good.
You were so close. You were correct in trying to use the setCartTemplate method. That is what you should be using. However, you were missing one essential method call that would allow Magento to even consider using it: you forgot to include the chooseTemplate method call. Note Magento's own checkout.xml file:
<block type="checkout/cart" name="checkout.cart">
<action method="setCartTemplate"><value>checkout/cart.phtml</value></action>
<action method="setEmptyTemplate"><value>checkout/cart/noItems.phtml</value></action>
<action method="chooseTemplate"/>
Look at that last method call, chooseTemplate. If you look in app/code/core/Mage/Checkout/Block/Cart.php you will see the following method, within which those familiar setCartTemplate and setEmptyTemplate methods are called, but because they are magic methods, they are not easily searchable in Magento's source, which is problematic for a lot of people:
public function chooseTemplate()
{
$itemsCount = $this->getItemsCount() ? $this->getItemsCount() : $this->getQuote()->getItemsCount();
if ($itemsCount) {
$this->setTemplate($this->getCartTemplate());
} else {
$this->setTemplate($this->getEmptyTemplate());
}
}
You were missing that chooseTemplate method call. This is what your own layout XML file should look like:
<checkout_cart_index>
<reference name="checkout.cart">
<action method="setCartTemplate"><value>mymodule/checkout/cart.phtml</value></action>
<action method="setEmptyTemplate"><value>mymodule/checkout/noItems.phtml</value></action>
<action method="chooseTemplate"/>
</reference>
</checkout_cart_index>
I recommend you update your code if it is still under your control. This is how Magento intended the cart templates to be updated. The common setTemplate method is too destructive for this task. Granularity was Magento's intention, so updates should maintain that granularity. I also recommend you mark this as the correct answer.
The method is setTemplate not setCartTemplate, like so:
<layout>
<checkout_cart_index>
<reference name="checkout.cart">
<action method="setTemplate"><value>mymodule/checkout/cart.phtml</value></action>
</reference>
</checkout_cart_index>
</layout>
Having trouble setting a block template in Magento's layout xml. I'm attempting to set the template of a child block, not the entire page layout (almost all docs out there explain how to set template of the layout).
Background: I'm updating a layout handle in my custom action, using the <update /> tag in my module's layout xml.
Essentially, I want to reuse the layout and blocks of the built in product view action, but provide custom templates for a few blocks. (Not just overrides, these need to be brand new templates that are only triggered on my custom action and are themselves overrideable).
My layout html:
<?xml version="1.0"?>
<layout version="0.1.0">
<mymodule_product_index>
<update handle="catalog_product_view" />
<reference name="content">
<block type="catalog/product_view"
name="product.info" output="toHtml" template="mymodule/product.phtml" />
</reference>
<reference name="product.info.bundle">
<action method="setTemplate"><template>mymodule/customtemplate.phtml</template></action>
</reference>
</mymodule_product_index>
</layout>
The setTemplate on product.info.bundle never works; it doesn't seem to affect layout at all. I've tried wrapping the <reference> in other <reference> nodes from parent blocks with no effect. Is it possible to replace block templates in this way? I feel that my problem stems from the fact I'm using an <update />.
By the way, I know my layout xml is being loaded and there are no errors, the rest of the file is working fine, caching is disabled, have cleared cache anyway, etc.
Your approach is almost correct.
Two things:
1. Set a new template instead of instantiating a new block
Instead of just assigning a different template to the product.info block, you are creating a new instance with the same name, replacing the original instance, and then the new template is set on that. Instead use this:
<mymodule_product_index>
<update handle="catalog_product_view" />
<reference name="product.info">
<action method="setTemplate">
<template>mymodule/product.phtml</template>
</action>
</reference>
</mymodule_product_index>
That should take care of the product view template in a clean way.
2. Handle processing order
If you look at where the view block product.info.bundle for the bundled products is declared, you will see it happens in the bundle.xml file, in a layout update handle called <PRODUCT_TYPE_bundle>.
Your code is referencing the block from the <[route]_[controller]_[action]> layout handle, i.e. <mymodule_product_index>.
The thing to be aware of here is the processing order of layout handles.
Roughly it is:
<default>
<[route]_[controller]_[action]>
<custom_handles>
The <PRODUCT_TYPE_bundle> handle belongs to the third type of layout handles, which means it is processed after the <mymodule_product_index> handle.
In essence, you are referencing the block product.info.bundle before it has been declared.
To fix this you will need to use the <PRODUCT_TYPE_bundle> handle as well. Of course this will effect every bundled product display. Using layout XML only there is no clean way around that.
Here are a few suggestions how to solve that problem.
You could create a separate route in your module to show the bundled products, and then include the <PRODUCT_TYPE_bundle> handle using an update directive for that page, too.
In your custom action controller, you could add another layout update handle that is processed after <PRODUCT_TYPE_bundle>.
You could use an event observer to set the template on the product.info.bundle block if it is instantiated. One possibility would be the event controller_action_layout_generate_blocks_after.
You get the idea, there are many ways to work around this, but they require PHP.
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've got a bestsellers module which I've written and it works great, however I want to be able to change the collection size it returns via the XML, rather than the php/phtml.
Something like this:
<block type="catalog/product_list" name="bestsellers" limit="3"
template="custom/bestsellers.phtml" />
or something like:
<block type="catalog/product_list" name="bestsellers"
template="custom/bestsellers.phtml">
<action method="setLimit">3</action>
</block>
Is this possible?
I'm currently changing the limit via the phtml with:
->setPageSize(3)
->setCurPage(1);
But that is hard coded and nasty, I need to be able to use my phtml file as template for many cases of the bestsellers module being called from anywhere with the XML + limit in the XML.
Thanks in advance if anyone can shed light on this!
The block Mage_Catalog_Block_Product_List inherits from the Varien_Object class which contains the methods getData() and setData(), as well as the magic methods get*() and set*(). These methods allow us to store (you guessed it) keyed-data within an object.
The <action /> tags in the XML allows us to perform method calls on the block instances. You're nearly there with your second example, but the syntax is:
<block type="catalog/product_list" name="bestsellers">
<action method="setLimit"><value>3</value></action>
</block>
Which is equivalent to:
<block type="catalog/product_list" name="bestsellers">
<action method="setData"><key>limit</key><value>3</value></action>
</block>
Which is roughly equivalent to:
$block = new Mage_Catalog_Block_Product_List();
$block->setLimit(3);
With the data set in the object we can now access through the getData() or get*() methods by calling $this->getLimit() or $this->getData('limit') making our block code:
->setPageSize($this->getLimit())
->setCurPage(1);
You should probably perform a check for the existence of the limit data first and provide a default value if none is provided in the XML.
Note: The name of the children in the <action /> tag don't matter. It's the order of the arguments that's important. We could just as well have called <action method="setLimit"><foo>3</foo></action> and it still would have worked.
I'm working on a custom Magento (1.3) theme and am wanting to add a left column.
I've created template/page/html/left.phtml with the html in.
In 2columns-left.phtml, i've added the following:
<?php echo $this->getChildHtml('left'); ?>
In page.xml, i've added the following:
<block type="page/html" name="left" as="left" template="page/html/left.phtml" />
What i'm not quite understanding is what that block type should be - it seems to work if I do page/html, core/template or page/html_header - what is this for and what is the correct value for this case, where I just want to effectively include a phtml file - page/html/left.phtml etc.
Thanks,
Ian
This is a simplified version of what's going on, but will
hopefully be enough to get you going.
Special Objects
There are three types of Objects that Magento considers "special". These are Models, Blocks, and Helpers. Rather than use class names for these objects Magento uses URI-like strings called class aliases . So this
page/html
corresponds to the Block class
Mage_Page_Block_Html
Class here is referring to PHP classes, not CSS classes.
Magento Page Rendering
A Layout Object is responsible for creating all the HTML for a Magento page.
A Layout Object is a collection of nested Block Objects.
Most Block Objects are Template Blocks, that is, the Block class inherits from the base Magento template block Mage_Core_Block_Template. Template Blocks are objects responsible for rendering a phtml template file.
So, when you specify a "type" in the XML Layout files, you're telling Magento.
I want to add a block object with the class foo/bar, using the template baz.phtml
In code, that's
<!-- "name" and "as" are used to identify the block in the layout, so that
PHP code can get a reference to the object. -->
<block type="foo/bar" name="myname" as="myname" template="path/to/baz.phtml" />
If all you want to do is render a template file, you can use
type="core/template"
However, by using a different value, like
type="page/html"
your phtml template file gets access to all the methods in
Mage_Page_Block_Html
Which means you could do something like
File: template.phtml
The core/template class doesn't have a getBaseUrl method, but the page/html class does.
If you're doing custom module development (as opposed to just theming), I usually create a Block Object in my own module that extends one of the base Magento blocks. This allows me to add my own methods to the block as I see fit. If you're only theming, page/html is a decent default.
The best type for this case is core/text_list because it concatenates every child HTML.
For testing you could use this example in your layout XML:
<block type="core/text_list" name="left" as="left">
<block type="core/text" name="test">
<action method="setText"><text>Hello World</text></action>
</block>
</block>
Block type for left column in magento theme
<block type="core/text_list" name="left" as="left" translate="label">
<label>Left Column</label>
</block>