Friday, April 30, 2010

Add new variable to order update e-mail

possible solution:

You need to override the Order model (app/code/core/Mage/Sales/Model/Order.php) and for the sendOrderUpdateEmail() method
you need to change this section
$mailTemplate->setDesignConfig(array('area'=>'frontend', 'store' => $this->getStoreId()))
Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $this->getStoreId()),
'order'     => $this,
'billing'   => $this->getBillingAddress(),
'comment'   => $comment
to this:
$mailTemplate->setDesignConfig(array('area'=>'frontend', 'store' => $this->getStoreId()))
Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $this->getStoreId()),
'order'     => $this,
'billing'   => $this->getBillingAddress(),
'comment'   => $comment,

In the e-mail template you can show the new var like this

{{var your_var_name}}

Thursday, April 29, 2010

How to add a block above the 3 columns in 3 columns layout

Problem: Adding on home page a block above the 3 columns

Possible solution:
Here is how i did it.
Edit app/design/frontend/{interface}/{theme}/layout/page.xml
In the <default> tag add this
<block type="core/text_list" name="top" as="top" translate="label">
<label>Top Row</label>
Now go to admin panel: Cms->Pages and edit the homepage.
I've created a new phtml file in which I placed the content I want on top
Let's say it's app/design/frontend/{interface}/{theme}/template/callouts/top_callout.phtml
In the design tab for 'Layout Update XML' I put this:

<reference name="top">
<block type="core/template" name="top.callout" template="callouts/top_callout.phtml" />
You can put every block you want here. I just used this as an example. Just put it inside
<reference name="top">
Now edit app/design/frontend/{interface}/{theme}/template/page/3columns.phtml
and add this line
<?php echo $this->getChildHtml('top') ?>
right under
<?php echo $this->getChildHtml('header') ?>
Save all files you edited and clear the contents of 'var/cache/'

I attached an image to see how it looks like.

View full size image

Thursday, April 22, 2010

How to change invoice status in Admin panel

Problem: When creating Invoice directly from Order in admin the invoice automatically gets marked as Paid. how can it be created with the status 'Pending' and marked as paid later.

Possible solution:
In order to create a 'pending' invoice, the payment method you use for the order must allow you to.
For that you need to add in the payment method's model this member:
protected $_canCapture = true;
You can add it right under
protected $_code  = 'PAYMENT CODE HERE';
For example if you want to do this for Check/money order you need to add the line above in app/code/core/Mage/Payment/Model/Method/Checkmo.php

After this when you create an invoice you will have an option near the save button to set the invoice status. (see picture attached). To create a pending invoice select 'Not capture'.
If you want to mark it later as paid edit the invoice and between the buttons on to one called 'Capture' (see picture). Well you get the idea....

Tuesday, April 13, 2010

Handle multi-language

Possible solution:
This is actually very simple. One store view = one language.
You download the desired language pack. For example French(France).
You should get a file called (or any other archive format)
Unzip this file over the root of your Magento application.
After that go to the admin panel. System->Configuration. Select from the top-left drop-down the store view you want to be in French and under the General tab 'Locale options' set Locale as French(France).
Save and clear the cache and you should have a store view in French. As for the products and categories again is simple. Edit the product you desire, Select from the top-left drop-down the French store view and enter the French values for the text attributes.

Monday, April 12, 2010

Move footer links to the top

Problem: How to move footer links to the top of the page
More details here: or here

Possible solution:
Edit this file:
Look for this line:
<block type="page/template_links" name="footer_links" as="footer_links" template="page/template/links.phtml"/>
It should be inside of an other <block> tag named footer.
Remove it from there and put it inside the <block> named 'header' (same file).
It should look like this (or close to it):
<block type="page/html_header" name="header" as="header">
<block type="page/template_links" name="top.links" as="topLinks"/>
<block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/>
<block type="core/text_list" name="" as="topMenu"/>
<block type="page/html_header" name="header" as="header">
<block type="page/template_links" name="top.links" as="topLinks"/>
<block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/>
<block type="core/text_list" name="" as="topMenu"/>
<block type="page/template_links" name="footer_links" as="footer_links" template="page/template/links.phtml"/>

Then edit app/design/frontend/{interface}/{theme}/template/page/html/header.phtml
Add this line at the end of the file (or where ever it fits your needs)
<?php echo $this->getChildHtml('footer_links') ?>
Clear the contents of dir var/cache and it should work. You might need to do some css work so the new added links would look nice.

Thursday, April 8, 2010

Adding a sidebar login box

How to add a login box on sidebar.
More details here

Possible solution:
First create a phtml file. Let's call it mini.login.phtml.
Place it in app\design\frontend\{interface}\{theme}\template\customer\form\mini.login.phtml
Make sure the form has the same action as in login.phtml Also give the inputs the same name as they have in login.phtml.

Edit app\design\frontend\{interface}\{theme}\layout\customer.xml
under the tag <customer_logged_out> put the following
<reference name="left">
<block type="customer/form_login" name="customer_mini_login" before="-" template="customer/form/mini.login.phtml"/>
Clear the cache and refresh.
This will put the mini.login at the top of your left column.If you want it lower play with the 'before' attribute. (You can even replace it with after)
See more details here.

The side effect of this is that all the pages that contain this block will have the meta-tille 'Customer Login'. (at least for version
To avoid this you have 2 options.
The 'quick and dirty' one.
Edit app\code\core\Mage\Customer\Block\Form\Login.php and in method _prepareLayout() remove this line:
$this->getLayout()->getBlock('head')->setTitle(Mage::helper('customer')->__('Customer Login'));
or remove the method completely (same effect).
This will work but the problem will reappear after an upgrade.
The 'by the book' option.
Overwrite the Mage_Customer_Block_Form_Login block. See tutorial here:
After that in the the class that extends Mage_Customer_Block_Form_Login create the method _prepareLayout() that does nothing. Just returns the current object.
protected function _prepareLayout()
return $this;

Thursday, April 1, 2010

Create bulk discount rules

Create bulk discount rules with unique coupon codes.
Details found here:
Possible solution:
This is not an extension, it's just a 'quick and dirty' script that I hope some day (when I have the time) will grow up and become an extension.

put the code below into a file (let's call it coupons.php) and follow the instructions below:

$mageFilename = 'app/Mage.php';

require_once $mageFilename;



ini_set('display_errors', 1);

Mage::register('isSecureArea', 1);
function generateUniqueId($length = null){
$rndId = crypt(uniqid(rand(),1)); 
$rndId = strip_tags(stripslashes($rndId)); 
$rndId = str_replace(array(".", "$"),"",$rndId); 
$rndId = strrev(str_replace("/","",$rndId));
if (!is_null($rndId)){
return strtoupper(substr($rndId, 0, $length));
return strtoupper($rndId);
function getAllCustomerGroups(){
//get all customer groups
$customerGroups = Mage::getModel('customer/group')->getCollection();
$groups = array();
foreach ($customerGroups as $group){
$groups[] = $group->getId();
return $groups;
function getAllWbsites(){
//get all wabsites
$websites = Mage::getModel('core/website')->getCollection();
$websiteIds = array();
foreach ($websites as $website){
$websiteIds[] = $website->getId();
return $websiteIds;
//read comments for each line
function generateRule(){
$uniqueId = generateUniqueId(10);
$rule = Mage::getModel('salesrule/rule');
$rule->setDescription('Generated by tzyganu');
$rule->setFromDate(date('Y-m-d'));//starting today
//$rule->setToDate('2011-01-01');//if you need an expiration date
$rule->setUsesPerCoupon(1);//number of allowed uses for this coupon
$rule->setUsesPerCustomer(1);//number of allowed uses for this coupon for each customer
$rule->setCustomerGroupIds(getAllCustomerGroups());//if you want only certain groups replace getAllCustomerGroups() with an array of desired ids 
$rule->setStopRulesProcessing(0);//set to 1 if you want all other rules after this to not be processed
$rule->setIsRss(0);//set to 1 if you want this rule to be public in rss
$rule->setIsAdvanced(1);//have no idea what it means :)
$rule->setSortOrder(0);// order in which the rules will be applied

//all available discount types
//by_percent - Percent of product price discount
//by_fixed - Fixed amount discount
//cart_fixed - Fixed amount discount for whole cart
//buy_x_get_y - Buy X get Y free (discount amount is Y)

$rule->setDiscountAmount('20');//the discount amount/percent. if SimpleAction is by_percent this value must be <= 100
$rule->setDiscountQty(0);//Maximum Qty Discount is Applied to
$rule->setDiscountStep(0);//used for buy_x_get_y; This is X
$rule->setSimpleFreeShipping(0);//set to 1 for Free shipping
$rule->setApplyToShipping(1);//set to 0 if you don't want the rule to be applied to shipping
$rule->setWebsiteIds(getAllWbsites());//if you want only certain websites replace getAllWbsites() with an array of desired ids

$conditions = array();
$conditions[1] = array(
'type' => 'salesrule/rule_condition_combine',
'aggregator' => 'all',
'value' => "1", //[UPDATE] added quotes on the value. Thanks Aziz Rattani [/UPDATE]
'new_child' => ''
//the conditions above are for 'if all of these conditions are true'
//for if any one of the conditions is true set 'aggregator' to 'any'
//for if all of the conditions are false set 'value' to 0.
//for if any one of the conditions is false set 'aggregator' to 'any' and 'value' to 0
$conditions['1--1'] = Array
'type' => 'salesrule/rule_condition_address',
'attribute' => 'base_subtotal',
'operator' => '>=',
'value' => 200
//the constraints above are for 'Subtotal is equal or grater than 200'
//for 'equal or less than' set 'operator' to '<='... You get the idea other operators for numbers: '==', '!=', '>', '<'
//for 'is one of' set operator to '()';
//for 'is not one of' set operator to '!()';
//in this example the constraint is on the subtotal
//for other attributes you can change the value for 'attribute' to: 'total_qty', 'weight', 'payment_method', 'shipping_method', 'postcode', 'region', 'region_id', 'country_id'

//to add an other constraint on product attributes (not cart attributes like above) uncomment and change the following:
$conditions['1--2'] = array
'type' => 'salesrule/rule_condition_product_found',//-> means 'if all of the following are true' - same rules as above for 'aggregator' and 'value'
//other values for type: 'salesrule/rule_condition_product_subselect' 'salesrule/rule_condition_combine'
'value' => 1,
'aggregator' => 'all',
'new_child' => '', 

$conditions['1--2--1'] = array
'type' => 'salesrule/rule_condition_product',
'attribute' => 'sku',
'operator' => '==',
'value' => '12',
//$conditions['1--2--1'] means sku equals 12. For other constraints change 'attribute', 'operator'(see list above), 'value'

//[UPDATE]if you work with Mangento EE and you want to link banners to your rule uncomment the line of code below
//Mage::getResourceModel('enterprise_banner/banner')->bindBannersToSalesRule($rule->getId(), array(1,2));//the array(1,2, ...) is the array with all the banners you want to link to the rule.

[UPDATE]. This was made for Magento 1.3 and lower. For versions >= 1.4 you have to add a new line
Add it just before
(Thanks Raj for pointing this out).

[UPDATE 1.1]
For Magento 1.4 and later there are store labels for the discount rules.
To add this construct the following array
$labels = array();
$labels[0] = 'Default store label';//default store label
$labels[1] = 'Label for store with id 1';
$labels[n] = 'Label for store with id n';
//add one line for each store view you have. The key is the store view ID

and before calling $rule->save(); add this line

(Thanks Sigmund for the update)
[/UPDATE 1.1]

Put the newly created file in the root of your magento installation (same level as index.php)
Walk through the file read all the comments and configure your discount settings (some programming skills are requred)
After everything is done add the following code at the end of the file (before php closing tag)

for ($i=1;$i<=200;$i++){//replace 200 with the number of coupons you want
[UPDATE 1.2]
If you want a nice script to import coupons using csv files with code, description and discount check this out:
Nice job Giel :). [/UPDATE 1.2]
call the page in you browser (http://your.magento.root/coupons.php) or run it from the command line.
Now check your admin for the new added rules.
PS (this does not work yet for 'Actions' tab).