Buy X get Y hack for Virtuemart 1.1.4 PDF Print E-mail

This is a hack. You will have to modify your original Virtuemart files, so first of all: backup your original files and your database before proceed.

Don't try this on a production site! The best thing I can suggest is that you fire up a test site and if you are satisfied with the results you can proceed with the production site.

We will go step by step with the modifications, and you can download the modifyed files on the bottom on this howto. I suggest to read it before you overwrite your files, it's better to know what was changed and why.

However if you don't have other hacks or modifications, you can simply replace the original files. 

 

What we need to modify:

 

1. We need to modify the jos_vm_product table. This will store the informations for the amount one have to buy in order to get the free items.
 

2. We need to modify the jos_vm_order_item table to store the purchased free items in order to save the items for the order history and confirmation emails.
 

3. We need to modify the admin form of the products in order to have two more fields which we can use to add and update these values.

  • 3.1. /administrator/components/com_virtuemart/classes/ps_product
  • 3.2. /administrator/components/com_virtuemart/classes/product.product_form.php
     

4. We need to modify the checkout process with the editable and the read only baskets as well as the minicart to display the items correctly.

  • 4.1. /administrator/components/com_virtuemart/html/basket.php
  • 4.2. /administrator/components/com_virtuemart/html/ro_basket.php
  • 4.3. /administrator/components/com_virtuemart/html/shop.basket_short.php

 

5. We need to insert and read the free items into the orders table and take care of the subtotal of the order. 

  • 5.1. /administrator/components/com_virtuemart/classes/ps_checkout.php
  • 5.2. /administrator/components/com_virtuemart/html/shop_browse_queries.php
  •  

 

6. We want to display in our shop that we have some special promotions on some of our products. This coud be done with an image or simply with a string. We will modify two more files to achieve this:

  • 6.1. /administrator/components/com_virtuemart/html/shop.browse.php - insert informations to use with the browse templates
  • 6.2. /administrator/components/com_virtuemart/html/shop.product_details.php - insert informations to use with flypage templates

  

7. We need to modify the invoice template in order to have listed the free items.

  • /components/com_virtuemart/themes/your template (default by default)/templates/pages/account.order_details.tpl.php 

 

8. We need to modify the confirmation email template in order to have listed the free items.

  • /components/com_virtuemart/themes/your template (default by default)/templates/order_emails/confirmation_email.tpl.php

 

These are the steps you have to follow in order to get these works:

 

1. Start your phpMyAdmin (or whatever you are using to modify your database) and select the jos_vm_product table. You need to add 2 more fields at the end of the table structure.

 

Pay attention to the default values. For the "buy" field you should set 1, for the "get" you can leave on 0. Otherwise you should correct one by one the existing items in your shop.

 


 

2. Again, in phpMyAdmin select the jos_vm_order_item table and add one more field after product_quantity field. Name it product_free_quantity.

 

 

 


 

3.1. Next we need to modify the ps_product file. You can find it in the /administrator/components/com_virtuemart/classes folder.

This is the file which store the class to manage your products. We will modify only 3 functions:the add, the update, and the validate.

Search for the fields array in the add function:

$fields = array ( 'vendor_id' => $vendor_id,

You will have only two results, the first in the add function, the second in the update function.

Replace the array with this:

$fields = array ( 'vendor_id' => $vendor_id,
  'product_sku' => vmGet($d,'product_sku'),
  'product_name' => vmGet($d,'product_name'),
  'product_desc' => vmRequest::getVar('product_desc', '', 'default', '', VMREQUEST_ALLOWHTML),
  'product_s_desc' => vmRequest::getVar('product_s_desc', '', 'default', '', VMREQUEST_ALLOWHTML),
  'product_thumb_image' => vmGet($d,'product_thumb_image'),
  'product_full_image' => vmGet($d,'product_full_image'),
  'product_publish' => $d['product_publish'],
  'product_weight' => vmRequest::getFloat('product_weight'),
  'product_weight_uom' => vmGet($d,'product_weight_uom'),
  'product_length' => vmRequest::getFloat('product_length'),
  'product_width' => vmRequest::getFloat('product_width'),
  'product_height' => vmRequest::getFloat('product_height'),
  'product_lwh_uom' => vmGet($d,'product_lwh_uom'),
  'product_unit' => vmGet($d,'product_unit'),
  'product_packaging' => (($d["product_box"] << 16) | ($d["product_packaging"]&0xFFFF)),
  'product_url' => vmGet($d,'product_url'),
  'product_in_stock' => vmRequest::getInt('product_in_stock'),
  'attribute' => ps_product_attribute::formatAttributeX(),
  'custom_attribute' => vmGet($d,'product_custom_attribute'),
  'product_available_date' => $d['product_available_date_timestamp'],
  'product_availability' => vmGet($d,'product_availability'),
  'product_special' => $d['product_special'],
  'child_options' => $d['child_options'],
  'quantity_options' => $d['quantity_options'],
  'product_discount_id' => vmRequest::getInt('product_discount_id'),
  'mdate' => $timestamp,
  'product_tax_id' => vmRequest::getInt('product_tax_id'),
  'child_option_ids' => vmGet($d,'included_product_id'),
  'product_order_levels' => $d['order_levels'],
  //hack by otx
  'buy' => $d['buy'],
  'get' => $d['get']);
  //end hack by otx

 

Or you can add only the last two lines between the //hack by otx and //end hack by otx. Pay attention to the "," and ";" on the end of the lines. Don't forget to add the ")" to the last line!

 

Replace the array in the update function, too. It's the same array so you can use the same code.

 

Now we need a validation for the "buy" item. After this modification when you will create a new product in your shop, even if you forget to set the correct values for the "buy" and "get" fields, which are 1 and 0, you will have this set after you save the product form.

Look for the following expression:

return $valid;

This is on the end of the validate function.

Insert this before the above line:

 

// hack by otx
       
 if ($d['buy'] ==0){
     $d['buy'] = 1;
 }
       
 // end hack by otx

So it will look like this:

// hack by otx
       
 if ($d['buy'] ==0){
     $d['buy'] = 1;
}
       
// end hack by otx
       
return $valid;

 

So far we have a working solution to store and update these values. Now we need to modify the admin form of the products in order to have fields which we can use to add and update these values.

 


 

3.2. Open the product.product_form.php. You can find it in the /administrator/components/com_virtuemart/html folder.

 

Search for the following lines (around 343):

        <?php echo vmToolTip( $VM_LANG->_('PHPSHOP_PRODUCT_FORM_DISCOUNTED_PRICE_TIP') ) ?>
        </td>
    </tr>

 Add after:

<!-- ******************** hack by otx *************************** -->
<!-- buy-get -->
   
   
     <tr class="row1">
      <td width="20%" ><div style="text-align:right;font-weight:bold;">
        <?php echo "Buy"; ?>:</div>
      </td>
      <td width="20%" >
<input type="text" class="inputbox"  name="buy" value="<?php $db->sp("buy"); ?>" 
size="10" maxlength="10"/>
      </td>
     </tr>
     <tr>
      <td width="20%" ><div style="text-align:right;font-weight:bold;">
        <?php echo "Get"; ?>:</div>
      </td>
      <td width="20%" >
<input type="text" class="inputbox"  name="get" value="<?php $db->sp("get"); ?>" 
size="10" maxlength="10" /><span style="text-align:left;font-weight:bold;">
        <?php echo "free"; ?></span>
      </td>
    </tr>
   
    <!-- end  buy-get -->
   
    <!-- ******************** end hack by otx *************************** -->

After this, if you edit some product in your admin area you will get this:

 

 

Notice the last two lines. You can use whatever combination you like it.

 


 

In order to use this feature we have to modify the checkout forms and the baskets.

 

4.1.Open the /administrator/components/com_virtuemart/html/basket.php

Search for the

$product_price = round( $product_price, 2 );

Should be around line 111. Add after:

// hack by otx

$amount = $cart[$i]["quantity"];
$buy = $ps_product->get_field($cart[$i]["product_id"],"buy");
if ($amount >= $buy){
$get = $ps_product->get_field($cart[$i]["product_id"],"get");
$total_quantity = $buy + $get;
$amount = (int)(($cart[$i]["quantity"] * ($total_quantity)) / $buy);
$free = $amount - $cart[$i]["quantity"];
}

if ($free>0){
$product_rows[$i]['quantity'] = $cart[$i]["quantity"].' + '.$free.'&nbsp;'.$VM_LANG->_('PHPSHOP_CART_FREE');
}else{
$product_rows[$i]['quantity'] = $cart[$i]["quantity"] + $free;
}

// end hack by otx

 Should look like this:

$product_price = round( $product_price, 2 );


// hack by otx

$amount = $cart[$i]["quantity"];
$buy = $ps_product->get_field($cart[$i]["product_id"],"buy");
if ($amount >= $buy){
$get = $ps_product->get_field($cart[$i]["product_id"],"get");
$total_quantity = $buy + $get;
$amount = (int)(($cart[$i]["quantity"] * ($total_quantity)) / $buy);
$free = $amount - $cart[$i]["quantity"];
}

if ($free>0){
$product_rows[$i]['quantity'] = $cart[$i]["quantity"].' + '.$free.'&nbsp;'.$VM_LANG->_('PHPSHOP_CART_FREE');
}else{
$product_rows[$i]['quantity'] = $cart[$i]["quantity"] + $free;
}

// end hack by otx


$product_rows[$i]['product_price'] = $GLOBALS['CURRENCY_DISPLAY']->getFullValue($product_price);

This will update the amount in the basket including the free items (and sets the variable for the amount of free items, which we will use later).

Next, still in the basket.php, look for the

$action_url = $mm_action_url.basename($_SERVER['PHP_SELF']);

line.

Replace the form below this line with:

 

//hack by otx
       
        if ($free >0) {
        $product_rows[$i]['update_form'] = '<form action="'. $action_url .'" 
method="post" style="display: inline;">
        <input type="hidden" name="option" value="com_virtuemart"  />
        <input type="text" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
class="inputbox" size="1" maxlength="4" name="quantity" 
value="'.$cart[$i]["quantity"].'"  />'.' + '.$free.$VM_LANG->_('PHPSHOP_CART_FREE').'
        <input type="hidden" name="page" value="'. $page .'" />
    <input type="hidden" name="func" value="cartUpdate"  />
    <input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'" />
    <input type="hidden" name="prod_id" value="'. $_SESSION['cart'][$i]["product_id"] .'" />
    <input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'"  />
    <input type="hidden" name="description" value="'. stripslashes($cart[$i]["description"]).'"  />
    <input type="image" name="update" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
src="'. VM_THEMEURL .'images/update_quantity_cart.png" border="0"  
alt="'. $VM_LANG->_('PHPSHOP_UPDATE') .'" align="absmiddle"/>
  </form>';
        $product_rows[$i]['delete_form'] = '<form action="'.$action_url.'" method="post" 
name="delete" style="display: inline;">
    <input type="hidden" name="option" value="com_virtuemart"  />
    <input type="hidden" name="page" value="'. $page .'" />
    <input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'" />
    <input type="hidden" name="func" value="cartDelete" />
    <input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
    <input type="hidden" name="description" value="'. $cart[$i]["description"].'" />
      <input type="image" name="delete" title="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" 
src="'. VM_THEMEURL .'images/remove_from_cart.png" border="0" 
alt="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" align="absmiddle" />
  </form>';}
        else{
    $product_rows[$i]['update_form'] = '<form action="'. $action_url .'" 
method="post" style="display: inline;">
        <input type="hidden" name="option" value="com_virtuemart" />
        <input type="text" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
class="inputbox" size="3" maxlength="4" name="quantity" value="'.$cart[$i]["quantity"].'"   />
        <input type="hidden" name="page" value="'. $page .'"     />
    <input type="hidden" name="func" value="cartUpdate"  />
    <input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
    <input type="hidden" name="prod_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"   />
    <input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'"  />
    <input type="hidden" name="description" value="'. stripslashes($cart[$i]["description"]).'" />
    <input type="image" name="update" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
src="'. VM_THEMEURL .'images/update_quantity_cart.png" border="0"  
alt="'. $VM_LANG->_('PHPSHOP_UPDATE') .'" align="absmiddle"  />
  </form>';
        $product_rows[$i]['delete_form'] = '<form action="'.$action_url.'" 
method="post" name="delete" style="display: inline;">
    <input type="hidden" name="option" value="com_virtuemart"  />
    <input type="hidden" name="page" value="'. $page .'"  />
    <input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'"  />
    <input type="hidden" name="func" value="cartDelete"  />
    <input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
    <input type="hidden" name="description" value="'. $cart[$i]["description"].'"   />
      <input type="image" name="delete" title="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" 
src="'. VM_THEMEURL .'images/remove_from_cart.png" border="0" 
alt="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" align="absmiddle"  />
  </form>';}
 
    //end hack by otx

You have to get this:

 

        /* UPDATE CART / DELETE FROM CART */
		$action_url = $mm_action_url.basename($_SERVER['PHP_SELF']);
		
		//hack by otx
       
        if ($free >0) {
        $product_rows[$i]['update_form'] = '<form action="'. $action_url .'" 
method="post" style="display: inline;">
<input type="hidden" name="option" value="com_virtuemart"  />
<input type="text" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
class="inputbox" size="1" maxlength="4" name="quantity" 
value="'.$cart[$i]["quantity"].'" />'.' + '.$free.$VM_LANG->_('PHPSHOP_CART_FREE').'
<input type="hidden" name="page" value="'. $page .'" />
<input type="hidden" name="func" value="cartUpdate" />
<input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'" />
<input type="hidden" name="prod_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
<input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'" />
<input type="hidden" name="description" value="'. stripslashes($cart[$i]["description"]).'" />
<input type="image" name="update" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
src="'. VM_THEMEURL .'images/update_quantity_cart.png" border="0"  
alt="'. $VM_LANG->_('PHPSHOP_UPDATE') .'" align="absmiddle"  />
</form>';
        $product_rows[$i]['delete_form'] = '<form action="'.$action_url.'" method="post" 
name="delete" style="display: inline;">
<input type="hidden" name="option" value="com_virtuemart" />
<input type="hidden" name="page" value="'. $page .'"   />
<input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'"  />
<input type="hidden" name="func" value="cartDelete"  />
<input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'" />
<input type="hidden" name="description" value="'. $cart[$i]["description"].'" />
<input type="image" name="delete" title="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" 
src="'. VM_THEMEURL .'images/remove_from_cart.png" border="0" 
alt="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" align="absmiddle"/>
</form>';}
        else{
    $product_rows[$i]['update_form'] = '<form action="'. $action_url .'" 
method="post" style="display: inline;">
<input type="hidden" name="option" value="com_virtuemart"   />
<input type="text" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
class="inputbox" size="3" maxlength="4" name="quantity" value="'.$cart[$i]["quantity"].'" />
<input type="hidden" name="page" value="'. $page .'"  />
<input type="hidden" name="func" value="cartUpdate"   />
<input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'" />
<input type="hidden" name="prod_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
<input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'"   />
<input type="hidden" name="description" value="'. stripslashes($cart[$i]["description"]).'"  />
<input type="image" name="update" title="'. $VM_LANG->_('PHPSHOP_CART_UPDATE') .'" 
src="'. VM_THEMEURL .'images/update_quantity_cart.png" border="0"  
alt="'. $VM_LANG->_('PHPSHOP_UPDATE') .'" align="absmiddle" />
</form>';
        $product_rows[$i]['delete_form'] = '<form action="'.$action_url.'" 
method="post" name="delete" style="display: inline;">
<input type="hidden" name="option" value="com_virtuemart"  />
<input type="hidden" name="page" value="'. $page .'"  />
<input type="hidden" name="Itemid" value="'. $sess->getShopItemid() .'" />
<input type="hidden" name="func" value="cartDelete"/>
<input type="hidden" name="product_id" value="'. $_SESSION['cart'][$i]["product_id"] .'"  />
<input type="hidden" name="description" value="'. $cart[$i]["description"].'" />
<input type="image" name="delete" title="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" 
src="'. VM_THEMEURL .'images/remove_from_cart.png" border="0" 
alt="'. $VM_LANG->_('PHPSHOP_CART_DELETE') .'" align="absmiddle"  />
</form>';}
 
    //end hack by otx

  
	} // End of for loop through the Cart

This is a little bit ugly, since I had to put some extra linebreaks in order to get this displayed on the site. In the original file the formatting is fine.

 

After this step, if somebody buy something in your shop, he will see the exact amount of purchased items as well as the free items he will get (hopefully :))

Something like this:

 

In the last line we have a product which is a promotional one.

Insert the following string in your language file (/administrator/components/com_virtuemart/languages) in order to get displayed the "free" expression after the free items. The above screenshot is taken from a romanian site, and we have "gratis" in this case.

 

'PHPSHOP_CART_FREE' => 'free'

Again, pay attention to the "," at the end of the lines, otherwise your site will go blank. The last one doesn't have to contain this, all the others should.

 


 

4.2. We need to modify the read only basket, too. Open the /administrator/components/com_virtuemart/html/ro_basket.php file.

Search for the line

/* Quantity Box */

around line100, and make like this:

/* Quantity Box */


/* hack by otx */

// hack by otx

$amount = $cart[$i]["quantity"];
$buy = $ps_product->get_field($cart[$i]["product_id"],"buy");
if ($amount >= $buy){
$get = $ps_product->get_field($cart[$i]["product_id"],"get");
$total_quantity = $buy + $get;
$amount = (int)(($cart[$i]["quantity"] * ($total_quantity)) / $buy);
$free = $amount - $cart[$i]["quantity"];
}

if ($free>0){
$product_rows[$i]['quantity'] = $cart[$i]["quantity"].' + '.$free.'&nbsp;'.$VM_LANG->_('PHPSHOP_CART_FREE');
}else{
$product_rows[$i]['quantity'] = $cart[$i]["quantity"] + $free;
}

// end hack by otx /* WEIGHT CALCULATION */

After this modification the customers will have the final confirmation something like this:


 

4.3. We need to display the free items in the minicart, too. Open the /administrator/components/com_virtuemart/html/shop.basket_short.php file.

Search for the

$amount += $cart[$i]["quantity"];

line.

 

Replace width:

// hack by otx

$buy = $ps_product->get_field($cart[$i]["product_id"],"buy");
$get = $ps_product->get_field($cart[$i]["product_id"],"get");
$total_quantity = $buy + $get;
if ($get>0) {
$amount += (int)(($cart[$i]["quantity"] * ($total_quantity)) / $buy);
}
else {
$amount += $cart[$i]["quantity"];
}

// end hack by otx

And the result:

As you can see (on the top right side) the minicart displays the amount of purchased items and the free items.

My client use the minicart only to display the total amount of purchased items and the final price, which seems logical given the fact that usualy there are a lot of items in the cart and we don't have the space to display all of them. 

 


 

5.1. Now we need to insert the free items into the orders table and take care of the subtotal of the order. Open the /administrator/components/com_virtuemart/classes/ps_checkout.php file and search for the

 

 $fields = array('order_id' => $order_id, 
'user_info_id' => $d["ship_to_info_id"],
'vendor_id' => $vendor_id,
'product_id' => $cart[$i]["product_id"],
'order_item_sku' => $dboi->f("product_sku"),
'order_item_name' => $dboi->f("product_name"),
'product_quantity' => $product_quantity,
'product_free_quantity' => $product_free_quantity,
'product_item_price' => $product_price,
'product_final_price' => $product_final_price,
'order_item_currency' => $GLOBALS['product_currency'],
'order_status' => 'P',
'product_attribute' => $description,
'cdate' => $timestamp,
'mdate' => $timestamp
);
$db->buildQuery( 'INSERT', '#__{vm}_order_item', $fields );
$db->query();

 Replace the entire array with

 
 

 /* otx check for free items */
$free = 0;
$amount = $cart[$i]["quantity"];
$buy = $ps_product->get_field($cart[$i]["product_id"],"buy");
if ($amount >= $buy){
$get = $ps_product->get_field($cart[$i]["product_id"],"get");
$total_quantity = $buy + $get;
$amount = (int)(($cart[$i]["quantity"] * ($total_quantity)) / $buy);
$free = $amount - $cart[$i]["quantity"];
}

if ($free>0){
$product_quantity = $cart[$i]["quantity"] + $free;
}else{
$product_quantity = $cart[$i]["quantity"];
}

$product_free_quantity = $free;

$fields = array('order_id' => $order_id,
'user_info_id' => $d["ship_to_info_id"],
'vendor_id' => $vendor_id,
'product_id' => $cart[$i]["product_id"],
'order_item_sku' => $dboi->f("product_sku"),
'order_item_name' => $dboi->f("product_name"),
'product_quantity' => $product_quantity,
'product_free_quantity' => $product_free_quantity,
'product_item_price' => $product_price,
'product_final_price' => $product_final_price,
'order_item_currency' => $GLOBALS['product_currency'],
'order_status' => 'P',
'product_attribute' => $description,
'cdate' => $timestamp,
'mdate' => $timestamp
);
$db->buildQuery( 'INSERT', '#__{vm}_order_item', $fields );
$db->query();


/* end otx check for free items */

 

Notice the product_free_quantity in the query array. Now we can store the amount of free items. 

 


 

5.2. We need to modify the /administrator/components/com_virtuemart/html/shop_browse_queries.php file in order to be able to insert and read from the buy and get fields in the jos_vm_product table (we have added these fields in the first step of this tutorial, remember?) 

 

Search for
 

 

/** Prepare the SQL Queries
*
*/
// These are the names of all fields we fetch data from 


$fieldnames = 

 

Replace the $fieldnames value with this

 

/*hack by otx */

/*
$fieldnames = "`product_name`,`products_per_row`,`category_browsepage`,
`category_flypage`,`#__{vm}_category`.`category_id`,
`#__{vm}_product`.`product_id`,`product_full_image`,`product_thumb_image`,
`product_s_desc`,`product_parent_id`,`product_publish`,
`product_in_stock`,`product_sku`, `product_url`,
`product_weight`,`product_weight_uom`,`product_length`,`product_width`,
`product_height`,`product_lwh_uom`,`product_in_stock`,
`product_available_date`,`product_availability`,`#__{vm}_product`.`mdate`, 
`#__{vm}_product`.`cdate`,`buy`,`get`";

*/

$fieldnames = "`product_name`,`products_per_row`,`category_browsepage`,
`category_flypage`,`#__{vm}_category`.`category_id`,
`#__{vm}_product`.`product_id`,`product_full_image`,`product_thumb_image`,
`product_s_desc`,`product_parent_id`,`product_publish`,
`product_in_stock`,`product_sku`, `product_url`,
`product_weight`,`product_weight_uom`,`product_length`,`product_width`, `product_height`,`product_lwh_uom`,`product_in_stock`, `product_available_date`,`product_availability`,`#__{vm}_product`.`mdate`, `#__{vm}_product`.`cdate`,`buy`,`get`";

/*end hack by otx */

 
   


 

6. We want to display in our shop that we have some special promotions on some of our products. This coud be done with an image or simply with a string. We will modify two more files to achieve this.

6.1. Open the /administrator/components/com_virtuemart/html/shop.browse.php file and search for

 

 // Add-to-Cart Button
if (USE_AS_CATALOGUE != '1' && $product_price != ""
&& $tpl->get_cfg( 'showAddtocartButtonOnProductList' )
&& !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
&& !ps_product::product_has_attributes( $db_browse->f('product_id'), true )) {

$tpl->set( 'i', $i );
$tpl->set( 'product_id', $db_browse->f('product_id') );
$tpl->set( 'product_in_stock', $db_browse->f('product_in_stock') );
$tpl->set( 'ps_product_attribute', $ps_product_attribute );
$products[$i]['form_addtocart'] = $tpl->fetch( 'browse/includes/addtocart_form.tpl.php' );
$products[$i]['has_addtocart'] = true;
}
else {
$products[$i]['form_addtocart'] = '';
$products[$i]['has_addtocart'] = false;
}

 

You will find around lines 415-431. Insert after 

 

// hack by otx

$buy = $db_browse->f('buy');
$get = $db_browse->f('get');

if ($db_browse->f('get') > 0) {
$string_promo_picture = '<div class="promo_picture">&nbsp;</div>';
$string_promo_details = '<div class="promo_details">'.$VM_LANG->_('VM_PROMO1').$buy.' + '.$get.' '.$VM_LANG->_('VM_PROMO2').'</div>';
}
else {
$string_promo_picture = '';
$string_promo_details = '';

}

// end hack by otx

 

So it will look like this:

 

...

// Add-to-Cart Button
if (USE_AS_CATALOGUE != '1' && $product_price != ""
&& $tpl->get_cfg( 'showAddtocartButtonOnProductList' )
&& !stristr( $product_price, $VM_LANG->_('PHPSHOP_PRODUCT_CALL') )
&& !ps_product::product_has_attributes( $db_browse->f('product_id'), true )) {

$tpl->set( 'i', $i );
$tpl->set( 'product_id', $db_browse->f('product_id') );
$tpl->set( 'product_in_stock', $db_browse->f('product_in_stock') );
$tpl->set( 'ps_product_attribute', $ps_product_attribute );
$products[$i]['form_addtocart'] = $tpl->fetch( 'browse/includes/addtocart_form.tpl.php' );
$products[$i]['has_addtocart'] = true;
}
else {
$products[$i]['form_addtocart'] = '';
$products[$i]['has_addtocart'] = false;
}

// hack by otx

$buy = $db_browse->f('buy');
$get = $db_browse->f('get');

if ($db_browse->f('get') > 0) {
$string_promo_picture = '<div class="promo_picture">&nbsp;</div>';
$string_promo_details = '<div class="promo_details">'.$VM_LANG->_('VM_PROMO1').$buy.' +
 '.$get.' '.$VM_LANG->_('VM_PROMO2').'</div>';
}
else {
$string_promo_picture = '';
$string_promo_details = '';

}

// end hack by otx




$products[$i]['product_flypage'] = $url;
$products[$i]['product_thumb_image'] = $product_thumb_image;
$products[$i]['product_full_image'] = $product_full_image;
$products[$i]['full_image_width'] = $full_image_width;
$products[$i]['full_image_height'] = $full_image_height; 
... 

 

After this if we have a product with buy x get y free enabled (this meens that you have changed the default buy 1 get 0 free values) we will have two variables, the $string_promo_picture and $string_promo_details, wich we can use in the browse templates, as well as the VM_PROMO1 and VM_PROMO2 strings wich we can use in the language files. We want to have in the browse templates somethink like this:

 

 

 

Notice the promo picture and the text below them, this will appear without any intervention as soon as you change the default Buy 1 Get 0 free values for a product. For this you should use those two variables in your browse template.

 

For example insert this in your browse template:

 

<?php if ($string_promo_details!='') /* if we have promotion for this product let display them*/
echo '<div class="promo">';
echo $string_promo_picture;
echo $string_promo_details;
echo '</div>';
?> 

 

Of course you should make a picture and copy to your site, and of course you should make the necessary changes in your template css file in order to get them displayed. The classes are: promo_picture and promo_details.(You have them in the above code by the way).

 

For example put somethink like this in your virtuemart template css:

 

div.promo_picture {
background: url( 'images/promo2.png' ) no-repeat 0px 0px transparent;
float: top;
width: 120px;
height:36px;
}

div.promo_details {
float: bottom;
}

 

These are not strictly related to the hack, and you will need some html and css skills to apply correctly. However I hope that the above examples will help.

 


 

6.2. Now we need these informations on the flypage, too. Open the /administrator/components/com_virtuemart/html/shop.product_details.php file and search 

 

 

$recent_products = $ps_product->recentProducts($product_id,$tpl->get_cfg('showRecent', 5));

 

 

Line 389, or somewhere around. Insert after

 

// hack by otx

$buy = $db_product->f('buy');
$get = $db_product->f('get');

if ($get > 0){
$tpl->set( "buy", $buy );
$tpl->set( "get", $get );
$string_promo_picture = '<div class="promo_picture">&nbsp;</div>';
$string_promo_details = '<div class="promo_details">'.$VM_LANG->_('VM_PROMO1').$buy.' + '.$get.' '.$VM_LANG->_('VM_PROMO2').'</div>';
}
else {
$string_promo_picture = '';
$string_promo_details = '';

}
$tpl->set( "string_promo_picture", $string_promo_picture );
$tpl->set( "string_promo_details", $string_promo_details );

// end hack by otx

 

 

Again, we will have two variables $string_promo_picture and $string_promo_details, which we can use in the flypage.

 

For example:

 

<?php if ($string_promo_details!='')
echo '<div class="promo">';
echo $string_promo_picture;
echo $string_promo_details;
echo '</div>';
?>

 

And - again - you have to take care of the css file of your template. 

 

div.promo {
float: right;
padding-left: 6px;
padding-right: 6px;
padding-top: 6px;
border: 1px solid #D44A07;
}

 

Note that these are only examples and probably doesn't apply to your virtuemart theme! 

 



7. We need to modify the invoice template in order to have listed the free items. Open the \components\com_virtuemart\themes\your theme name (default by default)\templates\pages\account.order_details.tpl.php file.

 

 

Search for (around line 279)

 

$product_id = null;
$dbi->query( "SELECT product_id FROM #__{vm}_product WHERE product_sku='".$dbcart->f("order_item_sku")."'");
$dbi->next_record();
$product_id = $dbi->f("product_id" );
?>
<tr align="left">
<td>
<?php
$dbcart->p("product_quantity");

 

Insert after the last line:

 

 

/* otx show the amount of free items */

$product_free_quantity = $dbcart->f("product_free_quantity");

if ($product_free_quantity > 0) {
echo ' (';
$dbcart->p("product_free_quantity");
echo $VM_LANG->_('PHPSHOP_CART_FREE');
echo ' )';
}
/* end otx show the amount of free items */

 

You should get this:

 

...

/* END HACK EUGENE */

$product_id = null;
$dbi->query( "SELECT product_id FROM #__{vm}_product WHERE product_sku='".$dbcart->f("order_item_sku")."'");
$dbi->next_record();
$product_id = $dbi->f("product_id" );
?>
<tr align="left">
<td>
<?php
$dbcart->p("product_quantity");

/* otx show the amount of free items */

$product_free_quantity = $dbcart->f("product_free_quantity");

if ($product_free_quantity > 0) {
echo ' (';
$dbcart->p("product_free_quantity");
echo $VM_LANG->_('PHPSHOP_CART_FREE');
echo ' )';
}
/* end otx show the amount of free items */

?>
</td>
<td><?php
if ($dbdl->next_record()) {
// hyperlink the downloadable order item ...

 

Search for (around line 333)
 

 

echo $CURRENCY_DISPLAY->getFullValue($item_price, '', $db->f('order_currency'));

?></td>
<td align="right"><?php $total = $dbcart->f("product_quantity") * $item_price;

 

Insert after the last line  

 

/* otx check for free items and correct the total*/

$product_free_quantity = $dbcart->f("product_free_quantity");
$total = $total - ($product_free_quantity * $item_price);



/* end otx check for free items */

 

 So now the subtotals are displaying with the correct values (without the free items prices).

 


  

8. We need to modify the confirmation email template in order to have listed the free items in the confirmation mail sent out after a purchase. Open the  /components/com_virtuemart/themes/your template (default by default)/templates/order_emails/confirmation_email.tpl.php file.

 

Search for (around line 179)

 

$my_subtotal = $my_qty * $price;

 

Insert after

  

/* otx check for free items and correct the total*/

$product_free_quantity = $dboi->f("product_free_quantity");
if ($product_free_quantity > 0) {
$my_subtotal = $my_subtotal - ($product_free_quantity * $price);
}
/* end otx check for free items */ 

 

Search for (around line 191)

 

 

<tr class="Stil1">
<td>
<?php
echo $my_qty; 

 

Insert after the last line  

 

 

/* otx show the amount of free items */

if ($product_free_quantity > 0) {
echo ' (';
echo $product_free_quantity;
echo $VM_LANG->_('PHPSHOP_CART_FREE');
echo ' )';
}

/* end otx show the amount of free items */

 
 


 

Well, that would be all. :)  

 

It would be nice if some developer from the Virtuemart team would be able to implement this hack, in order to have this available to everyone. A lot of stores would benefit from this modification.

Unfortunately I'm not a developer and I don't have the necessary skills  (nor time) to involve in this process. And even if it seems to be dificult to implement this hack for somebody who has only basic knowledge about Virtuemart, a developer could implement this in a couple of days, if not hours. So, if you know somebody who would be able to help us, making this done, please send him a link about this hack.

 

Thanks, and good luck!

 

 

You can download the modified files below, remember that even if you skip the tutorial and simply overwrite your original files, you still need to modify the jos_vm_product and jos_vm_order_item tables in order to have this work for you.

If you have further questions, feel free to ask for help in the forum, I will help as much as I can. 
 

 

Attachments:
FileDescriptionFile sizeDownloadsLast Modified
Download this file (vm_buyxgety_01.zip)vm_buyxgety_01.zipHack for Vrtuemart 1.1.2. Allows to sell items in buy x get y promotions (outdated and incomplete)45 Kb17812/13/10 09:47
Download this file (vm_buyxgety_02.zip)vm_buyxgety_02.zipHack for Vrtuemart 1.1.4. Allows to sell items in buy x get y promotions89 Kb9412/07/10 14:06
 
Comments (20)
Error in free product display
20 Friday, 23 December 2011 12:46
miguel barata
Hi again,

I think I solved the problem by changing in basket.php on // UPDATE CART / DELETE FROM CART

from

if ($free >0) {

to

if ($free >0 and $amount >= $buy) {

Kind Regards


Hi, I'm having the same issue as Chintan Desai reported, is there a solution available for this?

"I am facing a small problem with the display of the free item. everything work perfect until i update any product in the cart. The issue is if there are multiple products added in the cart and if i update the quantity of a single product(with a free product attached) there is a display of the free item associated with it and thats how it has to be but the issue is here all the products bellow that row will have the same no of item as free next to their respective quantity even though if that product is eligible for free offer or not. I hope i have managed to explain my problem... Please Help me out on this its a major problem that is stopping me to move ahead using your amazing hack..."

Kind Regards
Re:
19 Thursday, 30 June 2011 06:11
CorrineSingleton27
Houses are not very cheap and not everybody is able to buy it. Nevertheless, business loans are invented to aid people in such hard situations.
Another solution
18 Sunday, 15 May 2011 22:13
krogan.ro
Hy, this a great hack.

I have found another solution for this. Works on all promotion, disconted/free products are showed as a different product in the shopping cart. The cart is automatic updated on every transaction.

I can create this for you. Visit website, see article there.
My solution works for the latest version of Virtuemart and Joomla 1.5 .

Iulian
very nice
17 Friday, 06 May 2011 13:41
James
this is a great hack but i wanted a

(Buy x amount of product A get a free product B) like buy 10 hats get a free t-shirt
This seems to be more of a (Buy x product A get a free product A)
Hack for 1.1.6
16 Monday, 21 February 2011 14:52
Ben Lake
Hi... Just wondering if this hack will work for Virtuemart 1.1.6??
Buy X products Get 1 free
15 Wednesday, 12 January 2011 23:01
GFF
This hack worked. But I'm thinking I don't need buy 1 get 1 free for each product.

Can this hack be used to say buy any 9 items in the cart(store) and get 1 free?

So if I buy any ten items in the store the I get one free. They are all the same price.
Error in free product display
14 Tuesday, 30 November 2010 22:18
Chintan Desai
Hi,

I am facing a small problem with the display of the free item. everything work perfect until i update any product in the cart. The issue is if there are multiple products added in the cart and if i update the quantity of a single product(with a free product attached) there is a display of the free item associated with it and thats how it has to be but the issue is here all the products bellow that row will have the same no of item as free next to their respective quantity even though if that product is eligible for free offer or not. I hope i have managed to explain my problem... Please Help me out on this its a major problem that is stopping me to move ahead using your amazing hack...
download link
13 Friday, 12 November 2010 07:10
Marius
Hi, the download link is not working... can you post another one please? Your hack is fantastic! Great work!!!
REGARDING HACK
12 Monday, 27 September 2010 12:58
Shyam Sharma
The hack is working fine. User is aware of the buy x get y status. But there is not mention of this status in the backend of the site. That is virtuemart order tab doesnt provide any information regarding this status.
Good hack
11 Monday, 02 August 2010 10:32
jason
The is the best
Thanks
10 Friday, 25 June 2010 15:34
Tijs
Thank you for this hack, it work out well. Dispite the fact that you wrote this hack more than a year ago, did you make the modifications for the invoice?
Virtuemart 1.1.4
9 Friday, 25 June 2010 14:11
Tijs
phpMyAdmin int(11) if more than 100 products?

ps_product file = ps_product

languagefile = administrator/components/com_virtuemart/languages/shop/YOURLANGUAGE.php
Best Hack For VM
8 Thursday, 20 May 2010 08:48
paresh
This hack is very helpful for me, I never see this types of hack available at other site.
Best Luck for Future Development

Thanks
Paresh
Need help with Virtuemart Subtotal calculation and VAT change
7 Monday, 15 February 2010 09:52
Briggs
My web was fine all this time for last few months. in UK for last year we had VAT 15% now change back to 17.5%. so I thought it would be so simple of going in admin panel, virtuemart and than change tax rate.I have manage to do so how ever after the change the cart behaving weird.

I have got 4 step simple cart. the 4th step (preview order page is absolutely fine) but on page (steps of checkout cart) page 1,2,3 the sub total is wrong.

unit prices is right which is £10.00 VAT (tax) is right which £1.75 BUT SUBTOTAL is wrong £10.22 and again Subtotal: is wrong £10.22

Total VAT: £1.75 OK
Total: £11.97 The Calculation is ok

this happens to checkout steps 1, 2, and 3 the 4th step is fine....

also after changing tax the checkout steps and last step the tax showing ok but when I get confirmation email, the tax on that is still showing old 15% and not 17.5%

Please help

Thanks in advance

Briggs
Thank you
6 Monday, 14 December 2009 10:11
Tanna
[url=http://men.shoes54.com/cat1/Creative-Recreation-for-men.html]creative recreation[/url]
Great!
5 Wednesday, 04 February 2009 06:12
Brendon Hatcher
This is the neatest and most comprehensive documentation I have ever seen for a hack. Well done and thanks!

Brendon
language file
4 Tuesday, 04 November 2008 14:32
grikov1
hi,
thank for the custom hack, but which lang file to modify
Great
3 Thursday, 09 October 2008 13:42
Panos811
Great start. One question though, is it possible for the customer if he adds 2 products istead of showing 2 +2 free to show only the price of one product?
so if there is a promotion of buy get one free, if the customer adds one product the price is lets say $2 and if he adds anorher one the price remains $2!

Thanxs
nice tut!
2 Thursday, 25 September 2008 23:51
Preston
This is a great start. It should actually be part of the VM core code. Any progress with the invoices?
Excelent
1 Monday, 15 September 2008 13:45
Danny
ro: Super improvement pentru VM, abia astept sa imi fac timp sa o testez. Produsul gratuit nu poate fi si alt produs?

en: Great improvement for VM, I can wait to test it. BTW,, can the free product be another product?

Thanks for your work

Add your comment

Your name:
Your email:
Your website:
Subject:
Comment:
  The word for verification. Lowercase letters only with no spaces.
Word verification: