Magento – Price Template addPriceBlockType on Related and Upsell Items

layoutmagento-enterprisepriceproducttemplate

I was able to successfully create a new template for price in product listing as well as in product page using this:

<reference name='product_list'>
            <action method="addPriceBlockType">
                <type>simple</type>
                <block>catalog/product_price</block>
                <template>catalog/product/reseller/price.phtml</template>
            </action>
        </reference>

However, I could not do it in upsell or in related products block:

<reference name='catalog.product.related'>
            <action method="addPriceBlockType">
                <type>simple</type>
                <block>catalog/product_price</block>
                <template>catalog/product/reseller/price.phtml</template>
            </action>
        </reference>

The rendered template is still using the old price template.
How can I possibly change price template in these blocks?

Thank you.

Best Answer

This is my wild guess. Not sure whether it works or not. However it feels logical to me. First of all you are using addPriceBlockType() function, which is defined in Mage_Catalog_Block_Product_Abstract block class. Let us look what this method does.

public function addPriceBlockType($type, $block = '', $template = '')
    {
        if ($type) {
            $this->_priceBlockTypes[$type] = array(
                'block' => $block,
                'template' => $template
            );
        }
}

This method simply set _priceBlockTypes property with the given details. In our case, this property holds a values like this.

Mage_Catalog_Block_Product_Abstract::$_priceBlockTypes = array(
    'simple' => array(
        'block' => 'catalog/product_price',
        'template' => 'catalog/product/reseller/price.phtml'
    )
);

Layout job is over. Value is set correctly in Mage_Catalog_Block_Product_Abstract::$_priceBlockTypes. Now we need to see how price template get rendering in frontend. For this take a look on list.phtml. You can see a code like this.

<?php echo $this->getPriceHtml($_product, true) ?>

In related.phtml, this block is invoked like this.

<?php echo $this->getPriceHtml($_item, true, '-related') ?>

Now it is important to know what getPriceHtml() does. Again this is a property of Mage_Catalog_Block_Product_Abstract block class. Let us have a look.

public function getPriceHtml($product, $displayMinimalPrice = false, $idSuffix = '')
{
    $type_id = $product->getTypeId();
    if (Mage::helper('catalog')->canApplyMsrp($product)) {
        $realPriceHtml = $this->_preparePriceRenderer($type_id)
            ->setProduct($product)
            ->setDisplayMinimalPrice($displayMinimalPrice)
            ->setIdSuffix($idSuffix)
            ->toHtml();
        $product->setAddToCartUrl($this->getAddToCartUrl($product));
        $product->setRealPriceHtml($realPriceHtml);
        $type_id = $this->_mapRenderer;
    }

    return $this->_preparePriceRenderer($type_id)
        ->setProduct($product)
        ->setDisplayMinimalPrice($displayMinimalPrice)
        ->setIdSuffix($idSuffix)
        ->toHtml();
}

A close look reveals that, the method first retrieves product's type id and then use that value to prepare price section. ie

$type_id = $product->getTypeId();
.....
return $this->_preparePriceRenderer($type_id);

Now let us have a look what this protected _preparePriceRenderer() method does.

public function _preparePriceRenderer($productType)
{
    return $this->_getPriceBlock($productType)
        ->setTemplate($this->_getPriceBlockTemplate($productType))
        ->setUseLinkForAsLowAs($this->_useLinkForAsLowAs);
}

This method gets the block according to the type id that passed and set a template to that block and returns it. If we didn't set a custom block for price block, $this->_getPriceBlock($productType) will use default block Mage_Catalog_Block_Product_Price. In our case, this default block is using. Now this block is setting with a template using the method _getPriceBlockTemplate(). Now let us have a look on that method.

protected function _getPriceBlockTemplate($productTypeId)
{
    if (isset($this->_priceBlockTypes[$productTypeId])) {
        if ($this->_priceBlockTypes[$productTypeId]['template'] != '') {
            return $this->_priceBlockTypes[$productTypeId]['template'];
        }
    }
    return $this->_priceBlockDefaultTemplate;
}

As you can see it returns a template, if a template is set based on the type. Else it uses default template catalog/product/price.phtml.

This is the theory. Now let us think what is the problem exists here. We have template only for simple product type. Related products may be of any type. It may be simple, bundle, configurable etc. In the current situation, it uses your custom template only for simple related products. Not for any other types. So you need to set your custom template for every other product types

[edit]

File : app/design/frontend/<package>/<theme>/layout/local.xml

<layout>
    <catalog_product_view>
    <reference name='catalog.product.related'>
            <action method="addPriceBlockType">
                <type>simple</type>
                <block>catalog/product_price</block>
                <template>catalog/product/reseller/price.phtml</template>
            </action>
            <action method="addPriceBlockType">
                <type>bundle</type>
                <block>catalog/product_price</block>
                <template>catalog/product/reseller/price.phtml</template>
            </action>
            <!-- continue this for every type -->
    </reference>
    </catalog_product_view>
</layout>

Hope that make sense !

edit 2

It is wierd that, this method doesn't work. However there is an alternative solution for this. If you are no longer going to use the default price template, you can rewrite Mage_Catalog_Block_Product_Abstract block class and change the default template. However there is another problem. We cannot rewrite this class because it is an abstract class. So the easiest way to overwrite the method is "recreate" the same class in local pool.

File : app\code\local\Mage\Catalog\Block\Product\Abstract.php

<?php
class Mage_Catalog_Block_Product_Abstract extends Mage_Core_Block_Template
{
    /**
     * Rewrite constructor
     *
     */ 
    public function __construct()
    {
        parent::__construct();

        //set template using the method
        $this->addPriceBlockType('simple', 'catalog/product_price', 'catalog/product/reseller/price.phtml')

        //if the above method didn't work, use this along with that
        //sets your own template directly
        $this->__priceBlockDefaultTemplate = 'catalog/product/reseller/price.phtml';
    }

}

I have provided two ways to put your own custom price template. Use the last line, if the first condition fails again. If you are using the code, then you dont need to do any layout updates in anywhere. It will automatically use your custom price template every where it is displaying