Use of layout in Magento - magento

As I have seen for each Template file there exists a layout which connect blocks of particular Module. I struggled to understood each pieces in Magento, let me explain what I had done,
Consider a Template app\design\frontend\base\default\template\catalog\category\view.phtml
we have, $_category = $this->getCurrentCategory();
this function belongs to Block app\code\core\Mage\Catalog\Block\Category\view.php
What Magento's Template does is, it search for Layout instead of Block file,
i.e, Inside Layout file, app\design\frontend\base\default\layout\catalog.xml
we have, <block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
In this layout definition, the type attribute defines the block file,
i.e., Through layout file the Template gets the value of getCurrentCategory() function from Block.
Also we have <reference name="content">, <reference name="left"> which decides where to append the template.
My Question is,
Why can't Templates get the Value directly from Block without referring Layout?
Why Magento is not allowing us to do so?
What is the use of Layout while considering these 3 Block,Layout and Template?

1 - Why can't Templates get the Value directly from Block without referring Layout?
They can. Using your example:
<block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
This can be written as:
<block type="catalog/category_view" name="category.products">
And within the actual block (app/code/core/Mage/Catalog/Block/Category/View.php):
...
public function _construct()
{
parent::_construct();
// set the template here instead
$this->setTemplate('catalog/category/view.phtml');
}
...
2 - Why Magento is not allowing us to do so?
Magento does allow you to do so. The Magento layout system is very powerful, albeit very difficult to understand it initially.
3 - What is the use of Layout while considering these 3 Block,Layout and Template?
I will use this question to clear some of your misconceptions. As stated the Magento layout is very powerful and allows a lot of flexibility but at first glance this is not obvious. I will try explain best I can.
Imagine you created your own module within Magento and the Layout did not exist - everything was controlled within the 'controllers'. You would need to rewrite/extend/hack core Magento code to get things the way you wanted. If you wanted an extra widget on the category view page, you would need to override a controller method, or add your own controller.
The Magento Layout overcomes this by creating a global layout file which you can extend without messing with the core infrastructure.
Lets take your example.
On a category view page, if we wanted to change the above template, catalog/category/view.phtml, to something else, say my/category/view.phtml, we could do this:
<!-- this is the controller handle -->
<catalog_category_view>
<!--
by referencing, we are actually referring to a
block which has already been instantiated. the
name is the unique name within the layout.
generally all blocks should have a name and it
must be unique. however there can also be
anonymous blocks but thats out of scope of this
answer
-->
<reference name="category.products">
<!--
the layout allows us to fire methods within
the blocks. in this instance we are actually
firing the setTemplate method on the block
and providing a "template" argument.
this is the same as calling:
$this->setTemplate('my/category/view.phtml');
within the block.
-->
<action method="setTemplate">
<template>my/category/view.phtml</template>
</action>
</reference>
</catalog_category_view>
Just to reiterate:
Also we have <reference name="content">, <reference name="left"> which decides where to append the template.
This is incorrect. The "reference" tag allows you to reference blocks that are already instantiated. Just for completeness - the following example shows you how you can reference another block and place a block within it:
<!--
the default layout handle which is call on nearly all
pages within magento
-->
<default>
<!--
we are not referencing the "left" block
we could if we wanted reference "right",
"content" or any other blocks however
these are the most common
-->
<reference name="left">
<!--
add a block
in this example we are going to reference
"core/template" which translates to:
Mage_Core_Block_Template
which exists at:
app/code/core/Mage/Core/Block/Template.php
-->
<block type="core/template" name="my.unique.name.for.this.block" template="this/is/my/view.phtml" />
</reference>
</default>
Further reading: Introducing The Magento Layout

To answer your question, you need to dig down Magento's MVC approach,
A webpage is divided into several parts logically, for example, header, body, footer, etc., making the page layout organized and easy to adjust. Magento provides such flexibility through Layout XML files. Magento processes those layout files and render them into web pages.
Layout files act as detailed instructions to the application on how to build a page, what to build it with and the behavior of each building block.
Layout files are separated on a per-module basis, every module bringing with it its own layout file .The system is built this way in order to allow seamless addition and removal of modules without effecting other modules in the system.
In Magento, the View component of Model, View, Controller directly references system models to get the information it needs for display.
The View has been separated into Blocks and Templates. Blocks are PHP objects, Templates are "raw" PHP files that contain a mix of HTML and PHP. Each Block is tied to a single Template file. Inside a phtml file, PHP's $this keyword will contain a reference to the Template’s Block object.
Layout files contains <handlers> which are mapped to MVC controller, so expect your handler
<adminhtml_example_index> to be used in adminhtml/example/index controller page
and
<reference name="content"> means that the blocks or other references inside those blocks will be available in content block on your theme templates.
Each page request in Magento will generate several unique Handles. The 'View' of Magento’s MVC pattern implementation is divided in two parts: Layout and Template. The template represents a HTML block while layout defines the location of the block on a web page.
In Magento’s MVC approach, it's not the responsibility of the controller to set variables for the View (in Magento’s case, the view is Layout and Blocks). Controllers set values on Models, and then Blocks read from those same models.
Your controller’s job is to do certain things to Models, and then tell the system it’s layout rendering time. It’s your Layout/Blocks job to display an HTML page in a certain way depending on the state of the system’s Models.
In Magento, when a URL is triggered,
It determines Controller and action
Action Method manipulates Models
Action loads layout and starts rendering
Template, read from Models, via Blocks
Block and child blocks render into HTML

Related

Magento: overriding frontend phtml files without placing in default/default

I have a custom info.phtml file which is already working if placed at app\design\frontend\default\default\template\sales\order\info.phtml.
However, I do not want to use this approach since this is part of a module, so if later someone else overrides this file it'll brake the functionality. I've read about using custom blocks but I tried many different approaches without success.
Actually, the path you cite will only work when the theme package is set to default. The intended fallback theme for all files since CE1.4 is base/default. There's quite a lot to consider here, so let's break it down. Of course, being the end implementer of a Magento instance is luxurious because you can use any number of customization options without worrying about how to support other developers' needs. However, when developing a third party module for release to/consumption by others (as you are, it seems), then you have some tough decisions to make if you wish to ensure that output is modified in the way which your module intends/needs. Let's look at the template you mention, which is part of the means by which output is generated. This example contains several of the factors involved in the generation of output.
app/design/frontend/base/default/template/sales/order/info.phtml:
<?php $_order = $this->getOrder() ?>
<?php echo $this->getMessagesBlock()->getGroupedHtml() ?>
<div class="page-title title-buttons">
<h1><?php echo $this->__('Order #%s - %s', $_order->getRealOrderId(), $_order->getStatusLabel()) ?></h1>
<?php echo $this->getChildHtml('buttons') ?>
</div>
Are you in the right place?
The first question to ask is, "What do I need to change, and where?" If the answer lies in the output of a child block (e.g. the output of $this->getChildHtml('buttons')), then customizing the output means specifying an alternate child (with multiple possibilities for customization). If not, then the change is likely local to the template/block environment.
Is the change entity-related?
For third-party devs, the ideal solution is to avoid theme-dependent output whenever possible. For example, if you needed to change or add to the data available directly from one of the constituent objects, it is possible to modify that object or its behavior via Magento's configuration XML using configuration-based rewrites or via the event-observer architecture. In the current example, $this->getOrder() is an instance of Mage_Sales_Model_Order, $this is an instance of Mage_Sales_Block_Order_Info, and it is possible to rewrite either of these to a different class. Also, the sales_order_load_after method can be observed to modify properties of the order object.
Can translations be used?
If there is a need to modify just a string, it is often possible to effect this change via Magento's translation functionality. In a template, any string rendered via the __() method is passed through translation. This is very easy to modify for the end-implementer in a theme-specific translate.csv file. For third-party developers a little configuration XML allows to specify an additional translation CSV file, even for a core module.
Am I stuck with markup?
If there is a need to change the view markup being presented, it's necessary to modify the source of the markup, which most often is a template file. This can be effected in a couple of ways. In the case of the order info block, the sales/order/info.phtml template is defined in the Magento constructor:
class Mage_Sales_Block_Order_Info extends Mage_Core_Block_Template
{
//snip...
protected function _construct()
{
parent::_construct();
$this->setTemplate('sales/order/info.phtml');
}
//snip...
}
This usually means that there is no specified template in layout XML. The next step is to determine if the block is in fact instantiated via layout XML or in the controller. In the case of the latter, there's no way to manipulate the block via layout XML, so you'll need to use one of many possible Magento/PHP options to change the _template property. If the block is instantiated via layout XML, great - it's easy to specify some custom layout XML to point to an alternate template which will not be present in any theme; you just need to know the handle(s) and names which the block has been given, which can be determined by searching for the block instantiation markup (e.g. search *app/design/frontend/* for type="sales/order_info". This will lead you to *.../base/default/layout/sales.xml*:
<sales_order_view translate="label">
<label>Customer My Account Order View</label>
<update handle="customer_account"/>
<reference name="my.account.wrapper">
<block type="sales/order_info" as="info" name="sales.order.info">
<block type="sales/order_info_buttons" as="buttons" name="sales.order.info.buttons" />
</block>
<!-- etc. -->
It's possible to then use the handles and names to update the block's _template property in your module's custom layout update XML file, e.g.:
<sales_order_view>
<reference name="sales.order.info">
<action method="setTemplate"><tpl>my/custom/template.phtml</...>
<!--
Instead of <reference> you can use the 'block' attribute:
<action method="setTemplate" block="sales.order.info"><tpl>my/custom/template.phtml</...>
-->
This would allow you to put your custom template in the base/default template directory, where it belongs. However, you'll notice that this block is instantiated in a number of handle:
You might want to use a utility handle and <update /> directive to encapsulate the instructions into one place and provide it to all of the stock handles.
Nothing's foolproof!
This is one of several approaches, but it's not foolproof. Depending on your extension consumer audience, you might want to scan layout XML and template directories for customizations of/changes from the stock template and provide a notice to the admin.
If you need your custom info.phtml as part of a module, then declare it in module's xml. Then you can place your custom phtml file in app\design\frontend\whatever\somethingelse\template\sales\order and it will override it. For example, see this thread about how to override existing template file.
This is done from layout xml of your module.
Just put the code below in your layout xml with needed changes as per your namespace, module and controller action which call that file:
<checkout_onepage_index>//Use correct Controller action
<reference name="checkout.onepage.payment">//Change reference name as per your need
<action method="setTemplate">
<template>giftcard/checkout/onepage/payment.phtml</template>//Path of phtml file in yourmodule template folder
</action>
</reference>
</checkout_onepage_index>

CMS page add block magento

I have in CMS->page "home page" file. In content i am writing line like this:
{{block type="myfolder/newfile" template="myfolder/newfile.phtml"}}
I want to render in content file newfile.phtml. What i am doing wrong ?
My new file is under: app\design\frontend\default\themeas\template\myfolder\newfile.phtml
You need to give your block a name. That's how Magento will reference the block. Also, your block type must be valid in order for the block to render. For default blocks try using type="core/template"
Your new code should look like this:
{{block type="core/template" name="my.block.name" template="myfolder/newfile.phtml"}}
Another note about the type attribute, its not actually a directory/file structure, rather, it's a URI that is mapped with the Magento autoloader. "Core" relates back to the Mage_Core_Block_Core class (under the app/code/core/Mage/Core directory) and then the info after the slash relates to the folders inside of that directory. So type="core/template" resolves to this class Mage_Core_Block_Core_Template which is located at app/code/core/Mage/Core/Block/Template.php. All the type attribute is doing is telling Magento which methods you need to load inside of your block.
A couple other block types you can try are:
For Product Lists: catalog/product_list
For Text Lists (blocks that automatically render out child blocks): core/text_list
For Category Blocks: catalog/category_view
There are plenty more, a good way to find new ones is to look at a block that does a similar action to what you are trying to do, and find where it is defined in the XML.
If you want to pass variables to the block, you can do something like:
{{block type="core/template" name="my.block.name" myvariable="5" template="myfolder/newfile.phtml"}}
Since Magento 1.9.2.2, or equvivalent patch you also need to grant permissions to the new block. You do this in the backend:
System | permissions | blocks
I.e if you wish to show:
{{block type="catalog/product_bestseller" name="krillo.bestseller" template="catalog/product/bestseller.phtml"}}
Add your block name "catalog/product_bestseller" and set the status to "allowed"
I'd like to offer an alternative:
The above answers work fine, however it's my personal preference to not insert blocks in the content of a CMS page as clients can (and have) deleted this crucial line when trying to edit text and content using the WYSIWYG.
You could add the following in the the Layout > Layout update XML section of a CMS page:
<reference name="content">
<block after="-" type="your/block_type" name="block.name" template="your/block/template/file.phtml"/>
<action method="insert" ifconfig="your/block_type">
<block>block.name</block>
</action>
</reference>
This way, clients are less likely to edit this tab!
Hope this helps anyone else with this issue!

Set Magento block template in layout xml

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.

Magento - render phtml template file from layout update xml

I'm putting together my first Magento theme. Wee.
This site will have a large number of static pages, and I'm trying to determine the best method of getting that content into the system in an easily maintainable way. Ideally, this process can be managed by a team member with limited experience in magento (this is a key point).
Aside from these two main methods of including static "page" content:
1 - save page-content as a CMS static block, to be added to a
category page
2 - save page-content as a CMS page
it seems I should be able to just render a phtml template file (with page-content as real markup) from a combination of layout update xml directives (in a cms page / category page), or as a widget type of include.
Assuming my file structure looks like this:
/my_theme
/default
/varient
/template
/cms
/template
/category1
/category2
- page_content.phtml
I've tried planting this file into a cms page via a number of variations on:
<reference name="content">
<block type="core/template" name="content.current" as="content.current" output="toHtml" template="cms/template/category1/category2/page_content.phtml"
</reference>
in the layout update xml.
Alternatively, I've tried to render this file via content directives like:
{{block type="core/template" name="content.current" template="cms/template/category1/category2/page_content.phtml"}}
With (obviously) no luck so far.
Granted - there maybe reasons not to deal with static content in this way, but it may still be a viable alternative to the two steps already mentioned (image and link pathing, for example).
At any rate - I believe some combination of update xml or content directives should be workable, but I'm still getting my head around Magento layout and haven't figured out the correct method.
Any advice or explanations would be grand.
Cheers -
b[]x
For any future overflowers looking to figure this out:
{{block type='core/template' template='cms/template/category1/category2/page_content.phtml'}}
works for sure. Just tried it this morning without the name attribute and viola.

What Block Type for Left Column in Magento Theme?

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>

Resources