collective.xdv and multiple theme files - themes

I am having different theme HTML files for different site sections. There are some major layout differences depending if the page is the front page, or a certain subsection.
As far as I see the default behavior is just to have one HTML file:
http://pypi.python.org/pypi/collective.xdv#usage
What would be the best strategy to use multiple theme files, slight rule variations and collective.xdv?
Plone 4.1b.

We usually just utilize plain xdv and use the rules.xml (or whatever you want to call it) file to setup the theme templates leaving the corresponding properties in the collective.xdv controlpanel empty. Nesting rules gives you quite some fexibility when asigning different templates:
<?xml version="1.0" encoding="UTF-8"?>
<rules xmlns="http://namespaces.plone.org/xdv"
xmlns:css="http://namespaces.plone.org/xdv+css"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<theme css:if-content="body.section-front-page" href="frontpage.html" />
<theme css:if-path="/section/subsection/somefolder" href="somefolder.html" />
...
<rules css:if-content="#visual-portal-wrapper">
<!-- The default theme -->
<theme href="theme.html" />
<rules css:if-content="body.section-somefolder">
<!-- Secific rules for somefolder go here -->
...
</rules>
</rules>

You should use the Alternate Themes settings to define alternative layouts when the url matches a specific regular expression.
For example, we have a Plone site named "Plone" and accessible at url localhost:8080/Plone. To provide a different layout for the Home page, we can define the following in the registry (or TTW in the Plone Control Panel > XDV Settings section):
<record field="alternate_themes" interface="collective.xdv.interfaces.ITransformSettings" name="collective.xdv.interfaces.ITransformSettings.alternate_themes">
<field type="plone.registry.field.List">
<description>Define alternate themes and rules files depending on a given path. Should be of a form 'path theme rules' (or 'path rules' with xdv 0.4), where path may use a regular expression syntax, theme is a file path or URL to the theme template and rule is a file path to the rules file.</description>
<required>False</required>
<title>Alternate themes</title>
<value_type type="plone.registry.field.TextLine">
<title>Theme</title>
</value_type>
</field>
<value>
<element>^.*/Plone(/)?$ python://my.xdvtheme/templates/alternative/index.html python://my.xdvtheme/rules/alternative/index-rules.xml</element>
</value>
</record>
This way, the home page will use the alternative layout, while all the other pages will use the main layout specified in Theme template and Rules template
You can provide multiple definitions according to the different sections of your site.

My personal Plone site uses different theme and rules files for different parts.
Are you using the XDV control panel at /##xdv-settings?
In the Theme template and Rules File fields I put my default (i.e most used) files.
In the Alternate Themes textbox you can then provide alternate theme and rules files depending on a given path.
The format is path theme rules.
Here are some examples from my website's config:
.*/login_form|.*logged_out
/home/zope/production/theme/theme.html
/home/zope/production/theme/login.xml
/media/blog$
/home/zope/production/theme/blog.html
/home/zope/production/theme/blog.xml
/media/software
/home/zope/production/theme/software.html
/home/zope/production/theme/media.xml
As you can see, you can use regular expression syntax to match the paths.
The first line is for styling the login and logout pages.
The second for styling only my blog's landing page (henche the $)
the third styles my software page.
Works like a charm.

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

when customer login my related and upsells not display

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.

Where should I place block icons and CSS in magento extension

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.

Resources