Virtuemart
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