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>
Related
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
There exists
public Mage_Core_Block_Abstract::setParentBlock(Mage_Core_Block_Abstract $block)
Evidently it takes a block object as an argument. I have tried:
<reference name="myBlock">
<action method="setParentBlock">
<block><reference name="newParent"/></block>
</action>
</reference>
But, no luck.
Any ideas?
Is it even possible to someone pass a block object to a method, from within a layout file?
You can't call that method from layout XML files. The layout XML file's <action/> node is mainly (see below) used to pass strings as parameters. That means any method where the type hint explicitly requires an object
Mage_Core_Block_Abstract $block
is not meant to be called from the XML. It's a method used in the implementation of the system, and one the layout XML system is meant to protect you from accidentally calling.
Also, you can't use reference in the way you're trying
<reference name="newParent"/>
The <reference/> tag is only valid as an immediate ancestor of the top level layout handles (any other behavior caused by using reference in another location is an unintended implementation side effect, and I'd be wary of relying on said behavior)
Finally, you may be able to achieve what you want by using the "helper parameter" feature of the layout system.
<action method="setParentBlock">
<block helper="core/data/someMethod" arg1="foo" ...>
</action>
if you can find a helper class
Mage::helper('core/data');
Where someMethod returns the block you're after
Mage::helper('core/data')->someMethod(parameters,from,attributes,above);
but changing a block's parent mid-render is sort of abusing the layout system, and I'd advise against it (unless there's no other way to get at what you want).
You needn't worry about this at all, as the inverse is typically the way associations are built, but if you want to set a parent you can use the parent block attribute:
<block type="..." name="..." parent="parentblockname" ... />
I have a problem with my related and upsells.
When a customer login, my related and upsells not display in product_view.
The three most likely ways in which this can happen involve the following:
Layout XML
PHP/PHTML
CSS
Layout XML: grep your layout xml for <customer_logged_in> and see if there are any <remove /> nodes referring to these blocks. Also check for <action> tags with unsetChild method calls that refer to these blocks.
PHP/PHTML: It's possible that the templates and class definitions for these blocks have had logic added to them to check for customer logged in state. This would be an inefficient way to accomplish this, but it's possible. You'll need to check the templates (google for Magento template path hints) and the block classes in which they are rendered; see if they have been customized.
CSS: This is the most unlikely candidate, but I've seen developers set display:none based on <body> classes added via layout XML. This could be seen as an addBodyClass call in the <customer_logged_in> layout update handle, which I described how to find above.
I just want to understand the meaning of
<block type="page/html" name="root" output="toHtml" template="example/view.phtml">
I got many references from Google and understood many things about it but I am still unable to understand the formation of type="page/html" how to form a type for my custom module.
Please explain
type="A/B"
Let me know where this A and B come from?
For understanding more about magento block types following are some built-in block types which are widely used in layout.
core/template: This block renders a template defined by its template attribute. The majority of blocks defined in the layout are of type or subtype of core/template.
page/html: This is a subtype of core/template and defines the root block. All other blocks are child blocks of this block.
page/html_head: Defines the HTML head section of the page which contains elements for including JavaScript, CSS etc.
page/html_header: Defines the header part of the page which contains the site logo, top links, etc.
page/template_links: This block is used to create a list of links. Links visible in the footer and header area use this block type.
core/text_list: Some blocks like content, left, right etc. are of type core/text_list. When these blocks are rendered, all their child blocks are rendered automatically without the need to call thegetChildHtml() method.
page/html_wrapper: This block is used to create a wrapper block which renders its child blocks inside an HTML tag set by the action setHtmlTagName. The default tag is <div> if no element is set.
page/html_breadcrumbs: This block defines breadcrumbs on the page.
page/html_footer: Defines footer area of page which contains footer links, copyright message etc.
core/messages: This block renders error/success/notice messages.
page/switch: This block can be used for the language or store switcher.
This is a list of only commonly used block types. There are many other block types which are used in advanced theme implementations.
The A is a module's alias. In this case page is short for Mage_Page_Block (it is defined in app/code/core/Mage/Page/etc/config.xml if you want to see).
The B is the class name relative to the alias, initial letters of each word are capitalised. In this case html becomes Html and is appended to the resolved alias, so it is Mage_Page_Block_Html. This is probably found in the file app/code/core/Mage/Page/Block/Html.php because class names translate directly to locations in Magento.
Were you using a model alias instead of a block alias then page would be Mage_Page_Model instead. The same thing happens for resource models and helpers too. Your own module will need to define these in it's config if it is to have blocks, models and helpers.
<block type="page/html" name="root" output="toHtml" template="example/view.phtml">
page is a FrontendName defined in etc/config.xml file
html is a block class name
more details:
in this line type(type="page/html") define block class name related to your template(template="example/view.phtml">) and name is the unique for each block.
first see folder structure
app>local>namespace>modulename>etc>config.xml
we set FrontendName = 'mymodule'
app>local>namespace>modulename>Block>hello.php
in hello.php you created a function
class namespace_modulename_Block_Data extends Mage_Core_Block_Template
{
public function mydata()
{
$data = "Block is called";
return $data;
}
}
and now come to your layout xml page:
<block type="mymodule/data" name="xyz" template="example/view.phtml">
here mydata is frontend name
and now come to your template's
template/example/view.phtml page
here you can call directly mydata() function
like
<div>
<?php echo $this->mydata(); ?>
</div>
now you can get your output in browser
"Block is called"
i don't know about "B" type, but "A" refer to your module name tag in config.xml
example in config.xml:
<A><!-- script --></A>
No, you're not wrong. But the "<!-- script -->" may be confusing. Let's clarify: as the above answers stated, this is an alias, which consisted of two parts, the first part ("A") itself is the alias you define to your module's classes in your module's config.xml, the second is a path relative to the node's value. These together ("A" + capitalized "B") will be translated to a class name, using the first part (the "A" node's value) exactly as you define it (watch for upper/lowercase if you don't want hours of suffering) and the second part is capitalized after each underscore. So, start with the A/B example with a block and this config:
<config>
...
<global>
<blocks>
<A>Vendor_Module_Block</A>
</blocks>
</global>
...
</config>
In runtime A/B would resolved by the Magento config to Vendor_Module_Block_B which would then included by the autoload from the following path: public/app/local/Vendor/Module/Block/B.php. To get a better understanding I advise you to take a look at the Mage_Core_Model_Config::getGroupedClassName(), Mage_Core_Model_Config::getModelInstance() and Varien_Autoload::autoload().
I don't know about "B" type, but "A" refer to your module name tag in config.xml
An example in the config.xml file:
<A><!-- script --></A>
nb: i hope i'm not wrong..
My magento extension adds a new block (like the poll block for example) to the sidebar.
I am using the same html structure as that used by the poll block to make the block look like its part of the system.
i.e.
<div class="block block-myblock">
<div class="block-title">
<strong><span><?php echo $this->__('block title') ?></span></strong>
</div>...
I know that the icons on the poll block apear because of a CSS rule:
.block-poll .block-title strong { background-image:url(../images/i_block-poll.gif); }
that is returned from: /skin/frontend/base/default/css/widgets.css
and I also know that the image itself is stored at:
skin/frontend/default/default/images/
I have two Questions:
What would be the appropriate way to add my own require CSS rule to show the icon near my block ?
i.e. does .block-myblock .block-title strong { background-image:url(../images/i_block-myblock.gif); } go directly into some file ? and which file or is it added by the code of the block using some call like addCSS or something similar ?
What would be the appropriate path for me to store the i_block-myblock.gif image ?
please remember that this is all in the context of an extension, not local modifications to my own store.
This is a very good question and +1 for keeping the Magento wording in your CSS !
What I personnally do in order not to confuse developpers that may use my module is that I create a skin subfolder dedicated to the module. This way, it will be whether easy to find and cut/paste its css rules and images in the right theme folder whether running correctly for non experimented users.
1- Create the folder and files architecture
Like :
/skin/frontend/default/default/[your_module_name]/css/styles.css
/skin/frontend/default/default/[your_module_name]/images/ (containing all your module's images)
2- Edit your /skin/frontend/default/default/[your_module_name]/css/styles.css
...as usual but containing only CSS classes related to your module, ie :
.block-myblock .block-title strong { background-image:url(../images/i_block-myblock.gif); }
3- Call the CSS file from the layout XML of your module
Open, let's say /app/design/frontend/default/default/layout/[your_module_name].xml
and add the following lines after the first opening node like this :
<?xml version="1.0"?>
<layout version="0.1.0">
<!-- Code to add -->
<default>
<reference name="head">
<action method="addItem"><type>skin_css</type><name>[your_module_name]/css/styles.css</name><params/></action>
</reference>
</default>
<!-- [end] -->
.
.
.
</layout>
This should work while being respectful of Magento standards, not polluting existing themes and giving no headaches to developpers who wish to fully merge your skin with theirs.