How to detect if a price rule gets applied to a product

We were asked to write a simple module that makes it possible to display a rule-specific teaser on product pages when they are affected by catalog price rules.

So, our first question was: how can we even detect if a price rule is applied to a product?

The easiest Solutions

Model Mage_CatalogRule_Model_Rule offers two methods that seem quite interesting: loadProductRules and calcProductPriceRule.

loadProductRules will save any rule ids that are attached to the given product in the product’s collection:

// $_product is an instance of Mage_Catalog_Model_Product
$catalogRule = Mage::getModel('catalogrule/rule')->loadProductRules($_product);

$catalogRule will now contain an array: Array( [rule_id] => [irrelevant_number] ). If you want to know why we get an irrelevant number here, you can read up below.

While this is the fastest and easiest way to get any rules applied to our product, the most important thing to note is that it literally gives us *every* rule that is somehow connected. There are no filters applied which means we also get future and past rules and rules that are meant for any customer group or website. Depending on what you want to do this can be totally fine, of course.

Lets take a look at calcProductPriceRule. This handy method is returning our product’s price with any catalog rule applied to it. If there is no rule applied it will return NULL. This sounds great because we can use it do exactly what we need – detect whether a price rule gets applied to our product or not:

if( Mage::getModel('catalogrule/rule')->calcProductPriceRule($_product,$_product->getPrice()) ){
	echo 'Catalog price rule applied';
} else {
	echo 'No catalog price rule applied';
}

And yes, this one filters our rules by date, customer groups and website. The only downside of it is that it does more than we need it to do – which means it takes more resources than necessary.

So what are the alternatives?

An alternative way and also the way that we ended up going is reproducing what calcProductPriceRule does, but without actually calculating any prices. Essentially, it makes use of Mage_CatalogRule_Model_Resource_Rule::getRulesFromProduct and so will we:

Step 1: Set up your Model

class My_Module_Model_Catalogrule extends Mage_Core_Model_Abstract {
  /*
  * @param Mage_Catalog_Model_Product $product
  * @return array
  */
  public function getRulesFromProduct(Mage_Catalog_Model_Product $product)
  {
	  $productId  = $product->getId();
	  $storeId    = $product->getStoreId();
	  $websiteId  = Mage::app()->getStore($storeId)->getWebsiteId();
	  if ($product->hasCustomerGroupId()) {
		  $customerGroupId = $product->getCustomerGroupId();
	  } else {
		  $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
	  }
	  $dateTs     = Mage::app()->getLocale()->date()->getTimestamp();
  
	  return Mage::getResourceModel('catalogrule/rule')->getRulesFromProduct($dateTs, $websiteId, $customerGroupId, $productId);	  
  }	
}

Our method returns an empty array if the product does not have any price rules applied.

Step 2: Set up your Block

class My_Module_Block_Catalog_Product_Catalogrule extends Mage_Catalog_Block_Product_Abstract {
	
	protected $_rules;
	public function getRules(){
		if( is_null($this->_rules) ){
			$catalogrule = Mage::getModel('my_module/catalogrule');
			if(($product = $this->getProduct()) && ($rules = $catalogrule->getRulesFromProduct($product))){
				$this->_rules = $rules;
			} else {
				$this->_rules = false;	
			}
		}
		return $this->_rules;
	}
	
	public function hasRuleApplied(){
		if( $this->getRules() ){
			return true;
		}
		return false;
	}	
}

Step 3: Set up your template

Now we can do stuff like this in our block’s template:

<?php if($this->hasRuleApplied()): ?>
    <?php foreach($this->getRules() as $rule): ?>
    <div class="pricerule-teaser">
		<strong><?php 
        switch($rule['action_operator']){
            case 'by_percent':
                echo $this->__('%s%% Discount', round($rule['action_amount']));
            break;
            case 'by_fixed':
                echo $this->__('%s Discount', Mage::helper('core')->currency($rule['action_amount'], true, false));
            break;	
            case 'to_percent':
                echo $this->__('Only %s%% of the original price', round($rule['action_amount']));
            break;	
            case 'to_fixed':
                echo $this->__('Only %s', Mage::helper('core')->currency($rule['action_amount'], true, false));
            break;	
        } ?></strong>
    	<?php echo $this->__('until the %s !', date('dS M', $rule['to_time'])) ?>
    </div>
    <?php endforeach; ?>
<?php endif; ?>

Read up below if you want a list of all the values our $rule array stores.

Well and that’s it! Let us know if you have questions or ideas for improvement.

Continue reading How to detect if a price rule gets applied to a product

Adding Module pages to your Magento Sitemap

In earlier Magento versions it wasn’t possible to add additionals entries to your Magento Sitemap without overriding or extending Mage_Sitemap_Model_Sitemap.

Luckily, with the introduction of two events, sitemap_categories_generating_before & sitemap_products_generating_before, this became possible and therefore way simpler, too. Unless you don’t have to extend Mage_Sitemap_Model_Sitemap anyway, for example because you want to add images to your sitemap, you rather want to use these events.

Good to know…

Which event you want to choose depends on the changefreq and priority values you’d prefer for your additional page entries. You can look them up or change them in your Magento Sitemap configurations under System > Configuration > Catalog > Google Sitemap.

Even tho Magento is adding entries for category-, product- and CMS-pages, it does not fire an event for the latter one. Hence you have to choose between your category & product sitemap values.

In our example we prefer the product sitemap values. Therefore we go with the event sitemap_products_generating_before.

To it then!

Lets assume our custom module creates dynamic “News” pages and stores the page information, including the page URLs, within our model database table.

So first we add an event listener to the <global> tag in our module’s config.xml:

    <events>
        <sitemap_products_generating_before>
            <observers>
                <{your_unique_event_observer_name}>
                    <class>{Brand}_{Module}_Model_Observer</class>
                    <method>addPagesToSitemap</method>
                </{your_unique_event_observer_name}>
            </observers>
        </sitemap_products_generating_before>
    </events>

Then, in our module’s Observer, we let the method addPagesToSitemap add extra items to the product collection:

<?php
class {Brand}_{Module}_Model_Observer
{   
    function addPagesToSitemap(Varien_Event_Observer $observer){

        $sitemapItems = $observer->getEvent()->getCollection()->getItems();

        // Get your module's page collection including their urls
        // Adjust the following lines to your needs
        $collection = Mage::getModel('{brand}_{module}/pages')->getCollection()
            ->addFieldToSelect(array('page_id','url'))
            ->addFieldToFilter('display', 1);
        // My module stores the page path separately,
        // you might don't need this:
        $modulePagePath = Mage::helper('{my-modules-helper}')->getNewsPath();

        foreach($collection as $_item){
            $varienObject = new Varien_Object();
            // We don't want to override 
            // any existing product/category items
            $uniqueId = '{module}'.$_item->getPageId();         
            $varienObject->setId($uniqueId);

            // You might want to adjust this if your item
            // stores the complete url. Don't add the base url tho,
            // Mage_Sitemap_Model_Sitemap::generateXml adds it
            $varienObject->setUrl($modulePagePath . DS . $_item->getUrl());

            $sitemapItems[$uniqueId] = $varienObject;
        }
        $observer->getEvent()->getCollection()->setItems($sitemapItems);

        return $this;
    }
}

Well and that’s it! You can test it by manually generating your Magento Sitemap under Catalog > Google Sitemap.


(Tested in Magento 1.9.2.2)

Extra Renderer for Dynamic Thumbnails in Cart

(Magento 1.9.2.2 on Debian Jessie, running PHP 5.6.30 with Imagick 3.1.2)

In some cases it becomes necessary to show Dynamic Thumbnails, like SVG or canvas-gernerated images, in your cart rather than static product photos. In this article we address a possible solution for this.

Situation

We’ve developed a module that lets end customers put together their desired color-combination of a product by assigning patterns to a SVG via JavaScript. They can choose between over 50 colors for 4 separate product parts, therefore the number of possible color-combinations is quite huge.

Each color-combination is represented by a simple unqiue code (e.g. A: 22 B:09, C: 01, D: 11) that is stored into a hidden custom option input when added to cart.

Problem

Our item’s cart thumbnail needs to represent the actual color-combination (preferrably SVG into JPG). However, Magento doesn’t make Dynamic Thumbnails possible.

Our Solution

We add a custom cart-renderer that will overwrite Mage_Checkout_Block_Cart_Item_Renderer_Configurable::getProductThumbnail().

Alternatively, you could add the new renderer and assign it to a new template file that will for instance call a new method like getDynamicThumbnail(), without overwriting anything. However, in our case we had to work with the already existing renderer templates.

Step 1

We took a very similar approach like they did in this article. However, we made our module listen to a different Event, sales_quote_item_set_product:

<?xml version="1.0" encoding="utf-8"?>
<config>
	<!-- ... -->
	<frontend>
		<!-- ... -->
		<events>
		<!-- ... -->
			<controller_action_layout_load_before>
				<observers>
					<sales_quote_item_set_product>
				<observers>
					<my_cart_observer>
						<class>my_module/observer</class>
						<method>salesQuoteItemSetProduct</method>
					</my_cart_observer>
				</observers>
			</sales_quote_item_set_product>
		</events>
	</frontend>
	<!-- ... -->
</config>

Step 2

In our Observer method we first check if set quote item is the one attached to our SVG module. In our case we’re storing this product ID in our module’s settings so you might want to adjust this code to your business logic:

class My_Module_Model_Observer
{	 
	public function salesQuoteItemSetProduct(Varien_Event_Observer $observer){
		
		$product = $observer->getEvent()->getProduct();
		
		if($product->getId() != Mage::getStoreConfig('model_config/general/product_id'))
		{
			return $this;
		}
		
		$quoteItem = $observer->getEvent()->getQuoteItem();
		if(!($option = $quoteItem->getOptionByCode('product_type')) 
				|| $option->getValue() != 'customized_product')
		{
			$option = new Varien_Object();
			$option->setData(array(
				'product' => $product,
				'code' => 'product_type',
				'value' => 'customized_product'
			));		
			$quoteItem->addOption($option);
		}
		return $this;
	}	
}

So, what are we doing there? Well, what we don’t do is adding an actual new product type here. No, we simply assign a new option with the code “product_type” and the value “customized_product” (the name of the pseudo product-type; you can choose any name that isn’t already taken by actual product types). Why does this even work? Read up in the above linked article.

Step 3

Now we have to assign our custom Item Renderer, that will generate and add our Dynamic Thumbnails, to our new “pseudo product type”. We do this in a layout file – in our case our module’s own layout file. This is an example:

<?xml version="1.0" encoding="UTF-8" ?>
<layout version="0.1.0">
	<default>
		<reference name="cart_topcart">
        	<action method="addItemRender"><type>customized_product</type><block>my_module/cart_renderer</block><template>your/sidecart/renderer/layout.phtml</template></action>
		</reference>
	</default>	
	<checkout_cart_index>
		<reference name="checkout.cart">
        	<action method="addItemRender"><type>customized_product</type><block>my_module/cart_renderer</block><template>your/cart/renderer/layout.phtml</template></action>
		</reference>
	</checkout_cart_index>
	<checkout_onepage_index>
		<reference name="cart_sidebar">
        	<action method="addItemRender"><type>customized_product</type><block>my_module/cart_renderer</block><template>your/checkout/renderer/layout.phtml</template></action>
		</reference>
	</checkout_onepage_index>
	<checkout_onepage_review>
		<reference name="root">
        	<action method="addItemRender"><type>customized_product</type><block>my_module/cart_renderer</block><template>your/review/renderer/layout.phtml</template></action>
		</reference>
	</checkout_onepage_review>
</layout>

You’d have to adjust this to the renderer-layout files and references you are using. Also, keep in mind that depending on whether you already have other Modules addressing the Checkout/Cart process in place, you want to add them to the <depends> tags in your new module’s my_module.xml.

Step 4

Because our customizable product is a simple product belonging to a configurable product, we let our Renderer extend Magento’s Configurable Renderer:

class My_Module_Block_Cart_Item_Renderer extends Mage_Checkout_Block_Cart_Item_Renderer_Configurable
{	
    /**
     * @return Mage_Catalog_Model_Product_Image
     */
    public function getProductThumbnail()
    {
        $isCustomized	= false;
		$code 			= [];
		$product 		= $this->getChildProduct();
		
		if(($options = $this->getProductOptions())){
			/** 	
			 *	Get and form your necessary code.
			 *	Set $isCustomized to true during this process. 
			**/
		} 
		if( $isCustomized ){
			
			$helper = Mage::helper('my_module');
			/**
			 * We form following variables here:
			 * 
			 * $baseDir - the base path to the directory we'll store the connverted file
			 * $path - the absolute path to the directory we'll store the converted SVG files
			 * $filename - the name of the converted file. In our case it's the code combination.
			 * $svg -	the content of our svg with set color patterns. if you have trouble saving
			 * 			your SVG with patterns, write them directly (base64_encode) into your SVG
			 * 			instead of linking the image file.
			 * 
			**/
			$filepath = $path . DS . $filename;
			if(!is_file($filepath)){
				clearstatcache();
				
				$image = new Imagick();
				$image->readImageBlob($svg);
				
				$image->setImageFormat('jpeg');
      			$image->setImageCompressionQuality(70);
				$image->adaptiveResizeImage(100, 100);
				$image->writeImage($path . DS . $filename);
				
			}	
			return Mage::helper('my_module/image')->init($product, $baseDir . DS . $filename);
			
		} else {
			return parent::getProductThumbnail();
		}
	}
}

Step 5

Normally, getProductThumbnail() is returning Mage_Catalog_Model_Product_Image, called by $this->helper(‘catalog/image’)->init($product, ‘thumbnail’). This module does only access images within {ROOT}/media/catalog/product, however, we store our converted image files in {ROOT}/media/my/module. Therefore we make a custom helper “jump in”:

class My_Module_Helper_Image extends Mage_Core_Helper_Abstract
{
	protected $_product;
    public function init($product, $imageFile)
    {
        $this->setImageFile($imageFile);
        return $this;
    }
    public function resize($width, $height = null)
    {
        return $this;
    }	
    protected function setWatermark($watermark)
    {
        return $this;
    }
    protected function setImageFile($file)
    {
        $this->_imageFile = $file;
        return $this;
    }
    protected function getImageFile()
    {
        return $this->_imageFile;
    }
    public function __toString()
    {
       return Mage::getBaseUrl('media') . $this->getImageFile();
    }
}

In our case this helper doesn’t need to do more at the moment. But we could extend it anytime, if necessary.

This is pretty much it.

Let us know if you have ideas on improvements or some related questions!

Adding conditional Links to the top navigation

One of my today’s tasks was to add conditional links to our shop’s top navigation. Let me show you how we achieved that – it’s easy!

The very Basics

Adding new links is archieved quite easily by inserting following markup to your local.xml (app/design/frontend/{yourpackage}/{yourtheme}/layout/local.xml) or custom module template file, as we will do later on:

<?xml version="1.0"?>
<layout version="0.1.0">
<!-- ... -->
    <default>
        <reference name="top.links">
            <action method="addLink" translate="label title">
                <label>My link</label>
                <url>fancy/url</url>
                <title>My link</title>
                <prepare />
                <urlParams />
                <position>100</position>
                <aParams>
                    <class>top-link-mylink</class>
                </aParams>
            </action>
        </reference>
    </default>
<!-- ... -->
</layout>

As Magento comes with <customer_logged_in> and <customer_logged_out> handles, we can easily add links that are supposed to only show up for logged in (or only logged out) customers:

<?xml version="1.0"?>
<layout version="0.1.0">
     <customer_logged_in>
        <reference name="top.links">
            <action method="addLink" translate="label title">
                <label>My new link</label>
                <url>path/to/wherever</url>
                <title>My new link</title>
                <prepare />
                <urlParams />
                <position>50</position>
                <aParams>
                    <class>top-link-mynewlink</class>
                </aParams>
            </action>
        </reference>
    </customer_logged_in>
</layout>

In order to make already existing links, like “My account”, only show up for logged in customers, we have to remove them first. Also, in case you’re new to this, pay attention to the preferred way of getting an internal URL: instead of writing <url>customer/account</url> we want the available helper to fetch the URL:

<?xml version="1.0"?>
<layout version="0.1.0">
    <default>
        <reference name="top.links">
            <action method="removeLinkByUrl"><url helper="customer/getAccountUrl" /></action>
        </reference>
    </default>
    <customer_logged_in>
        <reference name="top.links">
            <action method="addLink" translate="label title">
                <label>My Account</label>
                <url helper="customer/getAccountUrl"/>
                <title>My Account</title>
                <prepare />
                <urlParams />
                <position>50</position>
                <aParams>
                    <class>top-link-account</class>
                </aParams>
            </action>
        </reference>
    </customer_logged_in>
</layout>

Conditional Links

Lets assume we want certain Links only to be displayed when our customer belongs to a certain customer group like, say, “Wholesale”… or really, any condition which isn’t being covered by an already existing handle.

Some days ago I came across a stackexchange thread where the accepted reply suggested to manage this by letting a top.link’s custom child block inject links to its parent…  While this approach actually works, it’s not how it’s supposed to be done. I’d want a handle (like its name suggests) handling the layout – meaning: I want to create <customer_group_[group_name]> handles.

So what we do is letting an Observer add our custom handlers. Observers listen to a certain event that they’re attached to. So, we want our Observer to listen to an event that’s for one dispatched globally and, for two, linked to the layout (I found this overview to be helpful). The event we want to observe is called controller_action_layout_load_before.

While we didn’t necessarily need to create a module for our previous layout updates, we need one now in order to set up our Observer. I created a module which is handling all things concerning updates on our shop’s navigation layout.

1. Creating a module

(just skip this if you already know how to create modules)

A. Architecture

Our module needs following files:

  • app/etc/modules/Montareno_Navigation.xml
  • app/local/Montareno/Navigation/etc/config.xml
  • app/local/Montareno/Navigation/Model/Observer.xml
  • app/design/frontend/montareno/default/layout/montareno_navigation.xml

Montareno = a custom name for your own pack of modules. Make sure this name isn’t already taken by community or core modules.
Navigation = your module’s name
montareno = your theme’s package name
default = your theme’s name

Always pay attention to Magento’s case sensitivity. Uppercase the first letter of your pack and module, but only the first – I haven’t tried it myself but some folks reported problems with uppercase letters following the first letter. The templates’s xml filename is the only exception as its name will be set in the config.xml and can have any name. However, it’s good habit to always name it by its pack’s and module’s name, so you will always know where it belongs to.

B. Registration & Configuration

Any layout updates concerning the Navigation can now move into the module’s own layout file. However, at this point Magento will ignore this and any other file belonging to our module. First, we want to make Magento be aware of our module and tell what our module offers (Magento is kind of a diva  😉 ).

The first file on our architecture’s list is a “registry file” (well, that’s what I call it) – it tells Magento “Hey, look, here’s another module, you’ll find it at Montareno/Navigation in the ‘local’ code directory”:

<?xml version="1.0" encoding="utf-8"?>
<config>
    <modules>
        <Montareno_Navigation>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Checkout />
                <Mage_Customer />
                <Mage_Wishlist />
            </depends>
        </Montareno_Navigation>
    </modules>
</config>

Note: You can remove the depends-Tag. However, in case you’re planning to extent your Navigation module, I find them to be a good start.

If Magento can locate the module we advertised, the first thing it does is looking for the modules configuration files located within etc. In our case it’ll only be one configuration file: config.xml. This file tells Magento where else to look, so obviously, this is the place where you tell Magento that your module comes with its own layout file – you write following lines into your config.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <Montareno_Navigation>
            <version>0.1.0</version>
        </Montareno_Navigation>
    </modules>
    <frontend>
        <layout>
            <updates>
                <Montareno_Navigation>
                    <file>montareno_navigation.xml</file>
                </Montareno_Navigation>
            </updates>
        </layout>
    </frontend>
</config>

Remember to adjust “Montareno_Navigation” to the pack & module name you’ve chosen (see above). Remember: case sensitivity!

2. Creating the observer

Now its time to open up the Observer.php and write our class Montareno_Navigation_Model_Observer:

class Montareno_Navigation_Model_Observer
{
/**
     * Adds layout handles customer_group_<group-name> 
     *
     * Event: controller_action_layout_load_before
     *
     * @param Varien_Event_Observer $observer
     */
    public function addCustomerGroupHandle(Varien_Event_Observer $observer){

        $customer = Mage::getSingleton('customer/session');
        if ($customer->isLoggedIn()) {
         
            $groupId = $customer->getCustomerGroupId();
            $groupName = preg_replace('#[^a-z0-9_]#', '', 
                str_replace(' ', '_',
                    strtolower(
                    Mage::getModel('customer/group')->load($groupId)->getCustomerGroupCode() 
                    ) 
                ) 
            );
            
            /* @var $update Mage_Core_Model_Layout_Update */
            $update = $observer->getEvent()->getLayout()->getUpdate();
            $update->addHandle('customer_group_' . $groupName);
            
        }
        
        return $this;
    }
}

I don’t think I have to explain what’s happening here and I also think you know what we have to do next: attach our Oberserver class to the event controller_action_layout_load_before

3. Attaching our observer to the event

Of course we do this in our module’s config.xml, too – simply add following lines after the closing modules tag:

   <!-- ... </modules> -->
    <global>
        <events>
            <controller_action_layout_load_before>
                <observers>
                    <customer_group_handle>
                        <class>Montareno_Navigation_Model_Observer</class>
                        <method>addCustomerGroupHandle</method>
                    </customer_group_handle>
                </observers>
            </controller_action_layout_load_before>
        </events>
    </global>
    <!-- <frontend> ... -->

These lines of xml are pretty straight forward. I chose to name my oberserver <customer_group_handle> but you can name it whatever you like – however, once again, I suggest you choose one that makes sense and, most importantly, isn’t already taken by other modules.

4. Yippie yay!

Yes, that’s it! Just clear the cache and there it is, our custom Navigation~

Displaying the child thumbnail instead of the configurable’s

Situation

Earlier in October we noticed that Magento’s “native” cart item renderer is not displaying the child thumbnail, despite our proper store configuration:

screenshot_checkout_shoppingcart

It kept showing the parent’s product thumbnail instead of displaying the child thumbnail.

Problem

I took a look at method getProductThumbnail:

 /**
 * Get product thumbnail image
 *
 * @return Mage_Catalog_Model_Product_Image
 */
 public function getProductThumbnail()
 {
   $product = $this->getChildProduct();
   if (!$product || !$product->getData('thumbnail')
   || ($product->getData('thumbnail') == 'no_selection')
   || (Mage::getStoreConfig(self::CONFIGURABLE_PRODUCT_IMAGE) == self::USE_PARENT_IMAGE)) {
     $product = $this->getProduct();
   }
   return $this->helper('catalog/image')->init($product, 'thumbnail');
 }

As you can see in line 75, it’s supposed to differentiate, however, it does not. This is because we need to check whether the config value and const value are identical (===) rather than just equal (==).

Solution

We can easily fix this by adding a new block that will extend Mage_Checkout_Block_Cart_Item_Renderer_Configurable. Montareno_Cart is one of our custom modules we were already using for cart modifications. If you don’t have such a custom module yet, just create one. This way we can overwrite method getProductThumbnail:

class Montareno_Cart_Block_Renderer_Configurable extends Mage_Checkout_Block_Cart_Item_Renderer_Configurable
 /**
 * Get product thumbnail image
 * FIX: comparison for identity rather than equality
 *
 * @return Mage_Catalog_Model_Product_Image
 */
 public function getProductThumbnail()
 {
     $product = $this->getChildProduct();
     if (!$product || !$product->getData('thumbnail')
     || ($product->getData('thumbnail') == 'no_selection')
     || (Mage::getStoreConfig(parent::CONFIGURABLE_PRODUCT_IMAGE) === parent::USE_PARENT_IMAGE)) {
       $product = $this->getProduct();
   }
   return $this->helper('catalog/image')->init($product, 'thumbnail');
 }
 
}

In order to make Magento actually use our modified renderer we need to replace checkout/cart_item_renderer_configurable in all cart layout files. Just take a look in your checkout.xml or the layout file of any other cart module you’re might using. This is an example of how our modifying module’s xml could look like:

    <default>
        <reference name="cart_sidebar">
        	<action method="addItemRender"><type>configurable</type><block>montareno_cart/renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action>
        </reference>
    </default>

    <checkout_cart_index>
        <reference name="checkout.cart">
        	<action method="addItemRender"><type>configurable</type><block>montareno_cart/renderer_configurable</block><template>checkout/cart/item/default.phtml</template></action>
        </reference>
    </checkout_cart_index>

    <checkout_onepage_review translate="label">
        <reference name="root">
            <action method="addItemRender"><type>configurable</type><block>montareno_cart/renderer_configurable</block><template>checkout/onepage/review/item.phtml</template></action>
        </reference>
    </checkout_onepage_review>

If you are offering multishipping in your store, you have to adjust these layout tags, too.

(At the time of writing we were working on a Magento CE 1.9.2.2 install on Ubuntu 12.04 / PHP 5.3.10)

Customer Registration not possible

Problem

When submitting the customers registration form, no account gets created. Instead, we get send back to on an empty registration form, customer registration not possible. No errors shown or logged.

Cause & Solution

Our registration’s template file (built from rwd) was missing the formkey-block needed for CSRF protection, so it was quite simple to fix:
Open app/design/frontend/drp/default/template/persistent/customer/form/register.phtml and add the following line somewhere between the form tags (I added it right after the opening tag):

<?php echo $this->getBlockHtml('formkey'); ?>

Sources

I got to the cause of this problem through this stackexchange question, thanks.

 

(At the time of writing we were working on a Magento CE 1.9.2.2 install on Ubuntu 12.04 / PHP 5.3.10)