Where should I place block icons and CSS in magento extension - magento

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.

Related

Use of layout in 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

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>

Setting canonical tags for categories in Magento

Is this possible, or is there some code that can be added so I can set a different canonical URL for categories in Magento? I can set for products fine.
Just found this question while searching for info about canonical URL support.
I'm not sure which version added this (couldn't find anything in release notes), but it is now supported out of the box in 1.7.0.2.
In admin: SYSTEM >> CONFIG >> CATALOG >> SEARCH ENGINE OPTIMIZATION
Last two options enable canonical URLs for categories and products.
Out of the box there is nothing for this that I am aware of. You will need to develop or build your own method of doing this.
You will need to create an entry in a layout.xml file to put an additional template in the head section of the page when you are on a category page (this would likely be in a catalog_Category_view block). You would also probably need a view file as well as a Block object to fetch the URL you want to use (technically you could put that in the view file, but having the block object is more "Magento").
Your layout.xml block would look something like this
<catalog_category_view>
<reference name="head">
<block type="canonical/canonical" name="head_url" as="head_url" template="ocaff/canonical/head.phtml" />
</reference>
</catalog_category_view>
This block references a head.phtml file. That file would contain:
<link rel="canonical" href="<?php echo $this->getCanonicalUrl() ?>" />
This calls back to a block object that has a function called getCanonicalUrl(). In this function you will find and determine what you want the canonical to be. Most likely you want this to be the URL key, but you may have other logic in mind there.
Canonical urls for product and category pages are supported by Magento from 1.5
In admin: SYSTEM >> CONFIG >> CATALOG >> SEARCH ENGINE OPTIMIZATION

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!

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.

Resources