1
votes

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.

3

3 Answers

5
votes

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:

sales.order.info usages

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.

0
votes

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.

0
votes

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>