Creating an Affiliate System with Ubercart

Last modified: November 8, 2007 - 03:49

We needed to launch a 2-tiered multi-affiliate program for the Ipod Fitness Center (www.ipodfitnesscenter.com) using Drupal. We also use the awesome Ubercart as our Drupal shopping cart, and by using the tools available we were able to build a very nice program to run our new affiliate program.

We first looked at the current Drupal Affiliate module, and felt that since it did not have a Link building function, or a tie-in to Ubercart, we would be better off rolling our own system. We’d hope that this module will continue to be enhanced.

To follow along with this thread, visit www.ipodfitnesscenter.com and login with:
username: demo
password: demo

To become an affiliate, you enter your info in a pretty standard Drupal form; it mainly makes sure we have your mailing address for your check, and your tax id number. Sign up form is here.

http://www.ipodfitnesscenter.com/affiliate

Once you join the program, you can use our site to build image or text links to your website.

http://www.ipodfitnesscenter.com/affiliate/imagelink - To build Image links (cool)
http://www.ipodfitnesscenter.com/affiliate/textlink - to build text links

You'll notice that these both create links that include your affiliate id (which is your Drupal uid) and all other info you need to place these on your website.

The commissions tab is next, and this is where you can see commission that you earn on the site. These commissions are written using Ubercart during the checkout process.

http://www.ipodfitnesscenter.com/affiliate/commission - to see commissions earned

Our site has a 2 tier affiliate program, we pay 20% commission to the affiliate, and 5% to the person that referred the affiliate to the site. Here is the code we used in our affiliate module to write the commissions using Ubercart’s hook_order()

<?php
function affiliate_order($op, $order, $status) // hoook_order for ubercart

{
global
$user;

if (
$op == 'update' && $status == 'pending' && uc_payment_balance($order) <= 1) {
// sale has been made write commision entries
// make sure my afid are set
   
if (empty($_SESSION[afid])) {
       
$_SESSION[afid] = getaffiliateforuser($user->uid, false);
       
$_SESSION[afidup] = getaffiliateforuser($user->uid, true);
    }
   
// get total of commissionalbe products
   
$comm_total = 0;
    foreach (
$order->products as $product) {
       
$x = node_load($product->nid);
        if (
$x->type == "supplements")     $comm_total += $product->price;
    }
    if (
$_SESSION[afid]) {
   
// write primany commission record
       
db_query("insert into {uc_affiliate_pay} (order_id, afid, commission, commission_notes) values ($order->order_id, $_SESSION[afid], $comm_total * .2, '20% commission on $comm_total sale  to $order->billing_first_name $order->billing_last_name')");   
    }
    if (
$_SESSION[afidup]) {
   
// write secondary commission record
           
db_query("insert into {uc_affiliate_pay} (order_id, afid, commission, commission_notes) values ($order->order_id, $_SESSION[afidup], $comm_total * .05, '5% commission on $comm_total sale to $order->billing_first_name $order->billing_last_name')");   

    }
  }
}
?>

The first couple of lines makes sure that my affiliate and affiliate sponsor are already set, (which they should be) they are set also set with hook_user() login, when you click an affiliate link, or in hook_menu(), this is one final check to make sure we have this set.

The next section...

<?php
foreach ($order->products as $product) {
       
$x = node_load($product->nid);
        if (
$x->type == "supplements")     $comm_total += $product->price;
    }
?>

Goes through the products in the order and calculates volume for products we pay commission on. We only pay 20% on the supplements product type. Once I have the total, we write a 20% and a 5% commission to a new table We created called uc_affiliate_pay. It has a simple structure as follows.

CREATE TABLE `uc_affiliate_pay` (
`key` bigint(20) NOT NULL auto_increment,
`order_id` bigint(20) default NULL,
`afid` bigint(20) default NULL,
`commission` double default NULL,
`commission_notes` varchar(60) default NULL,
PRIMARY KEY (`key`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=latin1;

The next affiliate tab is 'clicks' which keeps track of every click on an affiliate ad

http://www.ipodfitnesscenter.com/affiliate/clicks

Our affiliate code to track click and route the affiliate links to the correct pages was super simple.

<?php
function affiliate_start(){
$_SESSION[afid] = arg(4);
$target = arg(5);
$_SESSION[afidup] = getaffiliateforuser(arg(4), true);


db_query("insert into (affiliate_clicks} (affiliate_id, click_datetime, target,  referring_site) values ($_SESSION[afid], now(), '$target', '" . $_SERVER['HTTP_REFERER'] ."') ");
switch (
$target) {
case
'home' : drupal_goto("home");
case
'shopping' : drupal_goto("supplements");
case
'go' : drupal_goto("goipod");
case
'join' : drupal_goto("user/register");
case
'flash' : drupal_goto("flash.php");
case
'zeacaps' : drupal_goto("zeacaps");
default :
drupal_goto("supplements");
    }
}
?>

It grabs the affiliate id and the target page from the URL, then finds the sponsoring affiliate, it updates the click database (even tracks the site that sent the click using $_SERVER['HTTP_REFERER'], and then uses drupal_goto to navigate to the target page you selected when you built your link.

Ubercart was a great platform for us to use, and we were able to integrate order reporting easily. By making a call to uc_order_history we let our users see their order detail on a customized user profile page. Check it out here...

http://www.ipodfitnesscenter.com/users/demo

<?php
   
global $user;
    if (
$GLOBALS['user']->uid == arg(1)) {
    echo
'<div style="width: 99%;  padding-left: 1%;">
        <div class="cnt_hd_txt">
        <div id="fadeGreen">
            <div class="cnt_hd">Order History</div>'
;
            echo
uc_order_history($user->uid);
        echo
'</div>
        </div>
    </div>'
;
    }
   
$account = user_load(array('uid' => arg(1)));
   
drupal_set_title("Profile - ". $account->profile_fullname);
   
?>

(Yes Ryan, I did have to use drupal_set_title(), thanks for the tip)

If you click on the order, you'll see that we have including UPS and USPS tracking information in the order comments... so our users can easily see the status of their orders using Ubercart.

http://www.ipodfitnesscenter.com/user/52/order/40

One other thing you may have wondered about when you look at our affiliate link is why we used such a long path in the affiliate link. ie. Here is a sample link...

http://www.ipodfitnesscenter.com/ipod/fitness/nike/affiliate/5/go

We don't actually need the ipod - fitness - nike part of the URL, We could have used only affiliate, but by having our site keywords included in links pointing to our site, it increases our SEO rating for those pages.... (No big deal, but I had someone ask me about that when they made a link a few days ago.)

All in all, we are pretty happy with what this does for our affiliate needs. If you would like source code, or have questions, please feel free to ask... Also, we'd love it if you put up one of my affiliate ads on your website. Again, we pay out 20% on sales, and it's FREE.

Enjoy.
Jim Fulford
www.ipodfitnesscenter.com

PS. We did not build this as a ready to install Drupal module since we did some pretty extensive customization, but if you want to use any of the techniques we use, we’ll be glad to share ideas or source code.

Where i can get a source code?

Eugef - January 14, 2008 - 13:05

Your affiliate program is greate!
Where i can get a source code of it?

I am also interested in developing this module!
--------------
www.bytek.biz

I'm in the club too

t0ny - February 13, 2008 - 00:36

I'm in the club too

Here is the source code

phazer - February 14, 2008 - 07:35

This is not a stand alone module, you'll need to integrate wtih your databases, etc. But you are welcome to use it as your see fit. I had to delete a bunch of other code form my module that was specific to my database and site. So this is not drop in, but you'll have the code for all the coolest stuff like building the image links, and handline the commission in Ubercart.

<?php
function affiliate_perm() {
  return array(
'use affiliate');
}

function
affiliate_menu($may_cache) {

global
$user, $active;


 
$items = array();


 
$items[] = array(
   
'path' => 'affiliate',
   
'title' => t('Join Affiliate Link'),
   
'callback' => 'join_affiliate',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_CALLBACK
 
);


   
$items[] = array(
   
'path' => 'affiliate/join',
   
'title' => t('Join Affiliate Program'),
   
'callback' => 'join_affiliate',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_DEFAULT_LOCAL_TASK,
   
'weight' => 0

 
);



 
$items[] = array(
   
'path' => 'affiliate/imagelink',
   
'title' => t('Image Links'),
   
'callback' => 'link_generate_text',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_LOCAL_TASK,
   
'weight' => 1

 
);


 
$items[] = array(
   
'path' => 'affiliate/textlink',
   
'title' => t('Text Links'),
   
'callback' => 'link_generate_text',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_LOCAL_TASK,
   
'weight' => 2
 
);

 
$items[] = array(
   
'path' => 'affiliate/commission',
   
'title' => t('Commissions'),
   
'callback' => 'affiliate_commission',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_LOCAL_TASK,
   
'weight' => 3
 
);

 
$items[] = array(
   
'path' => 'affiliate/clicks',
   
'title' => t('Clicks'),
   
'callback' => 'affiliate_clicks',
   
'access' => user_access('use affiliate'),
   
'type' => MENU_LOCAL_TASK,
   
'weight' => 4
 
);


     
$items[] = array(
   
'path' => 'ipod/fitness/nike/affiliate',
   
'title' => t('Affiliate'),
   
'callback' => 'affiliate_start',
   
'access' => true,
   
'type' => MENU_CALLBACK
 
);
 

  return
$items;
}




function
join_affiliate_form() {
global
$user;

   
db_set_active('vlf');
   
$row = db_fetch_object(db_query("select * from users where userid = $user->uid"));
       
$form['aff_tag'] = array('#type' => 'markup', '#value' => 'By selecting Join, you agree to the IFC Affiliate <a href=affiliate/tc>Terms and Conditions</a>');

 
$form['affiliate'] = array(
 
'#type' => 'radios',
   
'#title' => t('Join the Ipod Fitness Affiliate Program'),
   
'#default_value' => $row->affiliate,
   
'#options' => array(
   
'1' => t('Join IFC Affiliate Program'),
   
'0' => t('No Thanks'),
      ),
);


 
$form['fullname'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Full Name / Company Name'),
   
'#size' => 30,
   
'#default_value' => $row->fullname,
   
'#maxlength' => 50,
   
'#description' => t('Enter your Full Name or Company Name'),
  );

 
$form['address'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Address'),
   
'#default_value' => $row->address,
   
'#size' => 40,
   
'#maxlength' => 60,
   
'#description' => t('Enter your Street Address'),
  );

 
$form['city'] = array(
   
'#type' => 'textfield',
   
'#title' => t('City'),
   
'#default_value' => $row->city,
   
'#size' => 30,
   
'#maxlength' => 50,
   
'#description' => t('Enter your City'),
  );

 
$form['state'] = array(
   
'#type' => 'textfield',
   
'#title' => t('State'),
   
'#default_value' => $row->state,
   
'#size' => 3,
   
'#maxlength' => 3,
   
'#description' => t('Enter your State'),
  );

 
$form['zip'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Zip Code'),
   
'#default_value' => $row->zip,
   
'#size' => 10,
   
'#maxlength' => 12,
   
'#description' => t('Enter your Zip Code'),
  );

 
$form['tax_id'] = array(
   
'#type' => 'textfield',
   
'#title' => t('SSN or Tax ID:'),
   
'#size' => 30,
   
'#default_value' => $row->tax_id,
   
'#maxlength' => 50,
   
'#description' => t('Enter your Social Security Number or Tax ID Number:'),
  );


$form['div_tag'] = array('#type' => 'markup', '#value' => '<hr>Optional - <b>If you have a VitaLife Member Number you can receive Affiliate Commissions with your VitaLife Compensation');

 
$form['vitalifeusername'] = array(
   
'#type' => 'textfield',
   
'#title' => t('VitaLife Member Number'),
   
'#default_value' => $row->vitalifeusername,
   
'#size' => 10,
   
'#maxlength' => 12,
   
'#description' => t('Enter your VitaLife Member Number'),
  );

 
$form['vitalifepassword'] = array(
   
'#type' => 'textfield',
   
'#title' => t('VitaLife Password'),
   
'#size' => 10,
   
'#default_value' => $xxxx,
   
'#maxlength' => 20,
   
'#description' => t('Enter your VitaLife Password'),
  );
 
 
 
$form['submit'] = array('#type' => 'submit',
   
'#value' => t('Submit'),
  );
 
 
  
$form['cancel'] = array('#type' => 'submit',
    
'#attributes' => array('onclick' => "return confirm('". t('Are you sure you want to quit without saving?') ."')"),
   
'#value' => t('Cancel'),
  );
   return
$form;


}



function
affiliate_commission(){

global
$user;

$countsql = "SELECT count(*) from uc_affiliate_pay where afid = $user->uid";
$sql = "SELECT uc_affiliate_pay.order_id, commission, commission_notes, created from uc_affiliate_pay
inner join uc_orders on uc_orders.order_id = uc_affiliate_pay.order_id
where afid = $user->uid order by created desc"
;

   
$result = pager_query($sql, 25, 0, $countsql);
   
$header = array('Order #','Date','Commission','Notes');   
    while (
$data = db_fetch_object($result)) {
   
   
$rows[] = array($data->order_id,
                   
date('m/d/y',$data->created),
                   
'$'.number_format($data->commission,2),
                   
$data->commission_notes);
        }
    
$table_attributes = array('id' => 'prod-table');   
   
$output = theme('table', $header, $rows, $table_attributes);
   
$output .= theme('pager', NULL, 25, 0);
    return (
$output);


}



function
affiliate_clicks(){

global
$user;

$countsql = "SELECT count(*) from affiliate_clicks where affiliate_id = $user->uid";
$sql = "SELECT * from affiliate_clicks where affiliate_id = $user->uid order by click_datetime desc";

   
$result = pager_query($sql, 25, 0, $countsql);
   
$header = array('Date','Target','Referring Website');   
    while (
$data = db_fetch_object($result)) {
   
   
$rows[] = array($data->click_datetime,
                   
$data->target,
                   
l($data->referring_site,$data->referring_site));
        }
    
$table_attributes = array('id' => 'prod-table');   
   
$output = theme('table', $header, $rows, $table_attributes);
   
$output .= theme('pager', NULL, 25, 0);
    return (
$output);


}




function
join_affiliate_form_submit($form_id, $form_values) {
}

function
join_affiliate() {
    return
drupal_get_form('join_affiliate_form');
}

function
join_affiliate_form_validate($form_id, $form_values)
{
}

function
link_generate_text()
{
    return
drupal_get_form("build_link_form");
}
   
   
function
build_link_form($form_values = NULL) {

global
$active, $user;

       
db_set_active('vlf');
       
$active = db_result(db_query("select affiliate from users where userid = $user->uid"));
       
db_set_active('default');

if (!
$active) {
   
drupal_set_message('You must join the Affiliate Program Before you can Create Affiliate Links');
   
drupal_goto("affiliate");
    return;
}

 
$form = array();

 
$form['#multistep'] = TRUE;

 
$form['#redirect'] = FALSE;

  if (
$form_values === NULL) {
   
// We're entering the form for the first time. Display the form!
   
$form['text'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Enter your Link Text'),
       
'#description' => t('Enter the Link Text here.'),
     
'#required' => TRUE,     
    );
   
   
$form['linkpage'] = array(
     
'#type' => 'select',
     
'#title' => t('Select Page'),
     
'#options' => array(
       
'home' => t('Home'),
       
'go' => t('Go'),
       
'join' => t('Join'),
       
'shopping' => t('Shopping'),    
       
'flash' => t('Flash'),
       
'zeacaps' => t('Zeacaps'),    
        ),
     
'#description' => t('Select the destination page you want the ad to link to.'),
     
'#required' => TRUE,           
      );
  
  
  if(
arg(1) == 'imagelink')
  {
  
$form['imagepick'] = array(
 
'#type' => 'radios',
 
'#title' => t('Select an Image'),
   
'#options' => array(
   
   
'<img src=http://www.ipodfitnesscenter.com/img/image_join_today_160.jpg ' => 'Join Today - Tall <div align=center><img src=/img/image_join_today_160.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/join_today_468.jpg ' => 'Join Today - Wide  <div align=center><img src=/img/join_today_468.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/get_fit_160.jpg ' => 'Get Fit - Tall  <div align=center><img src=/img/get_fit_160.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/get_fit_with_it_468.jpg ' => 'Get Fit - Wide  <div align=center><img src=/img/get_fit_with_it_468.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/zeacaps_160.jpg ' => t('Zeacaps - Tall <div align=center><img src=/img/zeacaps_160.jpg></div>'),
   
'<img src=http://www.ipodfitnesscenter.com/img/zeacaps_468.jpg ' => t('Zeacaps - Wide<div align=center><img src=/img/zeacaps_468.jpg></div>'),
 
'<img src=http://www.ipodfitnesscenter.com/img/vitalife_hpp_tall.jpg ' => t('VitaLife - Tall<div align=center><img src=/img//vitalife_hpp_tall.jpg></div>'),
     
'<img src=http://www.ipodfitnesscenter.com/img/vitalife_hpp_wide.jpg ' => t('VitaLife - Wide<div align=center><img src=/img/vitalife_hpp_wide.jpg></div>'),
   
   
  ),
);
}  
  
   
$form['submit'] = array(
     
'#type' => 'submit',
     
'#value' => t('Submit'),
    );
  }
  else {
   
// $form_values is populated, which means we're coming in a second
    // time. Let's display the results in addition to the original form fields.
   
  
$form['results'] = array(
     
'#type' => 'item',
     
'#title' => t('Please copy the below code and paste it in your web site page'),
     
'#value' => _build_text_link_format_values($form_values),
    );

   
    
$form['text'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Enter your Link Text'),
       
'#description' => t('Enter the Link Text here.'),
     
'#required' => TRUE,     
    );
   
   
$form['linkpage'] = array(
     
'#type' => 'select',
     
'#title' => t('Select Page'),
     
'#options' => array(
       
'home' => t('Home'),
       
'go' => t('Go'),
       
'join' => t('Join'),
       
'shopping' => t('Shopping'),    
       
'flash' => t('Flash'),
       
'zeacaps' => t('Zeacaps'),    
        ),
     
'#description' => t('Select the destination page you want the ad to link to.'),
     
'#required' => TRUE,           
      );
  
      if(
arg(1) == 'imagelink')
  {
  
$form['imagepick'] = array(
 
'#type' => 'radios',
 
'#title' => t('Select an Image'),
   
'#options' => array(
   
   
'<img src=http://www.ipodfitnesscenter.com/img/image_join_today_160.jpg ' => 'Join Today - Tall <div align=center><img src=/img/image_join_today_160.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/join_today_468.jpg ' => 'Join Today - Wide  <div align=center><img src=/img/join_today_468.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/get_fit_160.jpg ' => 'Get Fit - Tall  <div align=center><img src=/img/get_fit_160.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/get_fit_with_it_468.jpg ' => 'Get Fit - Wide  <div align=center><img src=/img/get_fit_with_it_468.jpg></div><br>',
   
'<img src=http://www.ipodfitnesscenter.com/img/zeacaps_160.jpg ' => t('Zeacaps - Tall <div align=center><img src=/img/zeacaps_160.jpg></div>'),
   
'<img src=http://www.ipodfitnesscenter.com/img/zeacaps_468.jpg ' => t('Zeacaps - Wide<div align=center><img src=/img/zeacaps_468.jpg></div>'),
     
'<img src=http://www.ipodfitnesscenter.com/img/vitalife_hpp_tall.jpg ' => t('VitaLife - Tall<div align=center><img src=/img//vitalife_hpp_tall.jpg></div>'),
     
'<img src=http://www.ipodfitnesscenter.com/img/vitalife_hpp_wide.jpg ' => t('VitaLife - Wide<div align=center><img src=/img/vitalife_hpp_wide.jpg></div>'),
  ),
);
}  

   
   

   
$form['submit'] = array(
     
'#type' => 'submit',
     
'#value' => t('Submit'),
    );

  }

  return
$form;
}

function
affiliate_start(){
$_SESSION[afid] = arg(4);
$target = arg(5);
$_SESSION[afidup] = getaffiliateforuser(arg(4), true);

//    drupal_set_message('Affiliate ID: '. $_SESSION[afid]);
//    drupal_set_message('Upline Affiliate ID: '. $_SESSION[afidup]);
// drupal_set_message($target . ' ' . $_SESSION[afid]);

db_query("insert into affiliate_clicks (affiliate_id, click_datetime, target,  referring_site) values ($_SESSION[afid], now(), '$target', '" . $_SERVER['HTTP_REFERER'] ."') ");
switch (
$target) {
case
'home' : drupal_goto("home");
case
'shopping' : drupal_goto("supplements");
case
'go' : drupal_goto("goipod");
case
'join' : drupal_goto("user/register");
case
'flash' : drupal_goto("flash.php");
case
'zeacaps' : drupal_goto("zeacaps");
default :
drupal_goto("supplements");
    }
}

function
_build_text_link_format_values($form_values = array()) {
  global
$user;
 
$header = array(t('Key'), t('Value'));
 
$rows = array();
 
 
//print "<pre>";print_r($form_values);
 
if(arg(1) <> 'imagelink')
  {
     
$affliate_link = '<a href="http://www.ipodfitnesscenter.com/ipod/fitness/nike/affiliate/'.$user->uid.'/'.$form_values['linkpage'].'">'.$form_values[text].'</a>';
  }
  else
  {
     
$affliate_link = '<a href="http://www.ipodfitnesscenter.com/ipod/fitness/nike/affiliate/'.$user->uid.'/'.$form_values['linkpage'].'">'. $form_values['imagepick'] .' alt="'.$form_values[text].'" border="0"></a>';
  }

  return
'<textarea cols="71" rows="6" style="font-size:18px;" readonly>'.htmlentities($affliate_link).'</textarea>'.
          
'<br/><br/>'.'<label>Your link would look like:</label><br/>'.$affliate_link;
}




function
affiliate_user($type, &$edit, &$user, $category = NULL) {

switch (
$type) {
case
'login': {
   
//drupal_set_message('Affiliate ID: '. getaffiliateforuser($user->uid, false));
   
$_SESSION[afid] = getaffiliateforuser($user->uid, false);
//    drupal_set_message('Upline Affiliate ID: '. getaffiliateforuser($_SESSION[afid], true));
   
$_SESSION[afidup] = getaffiliateforuser($user->uid, true);
    break;
    }

    }
}


function
affiliate_order($op, $order, $status) // hoook_order for ubercart

{
global
$user;

if (
$op == 'update' && $status == 'pending' && uc_payment_balance($order) <= 1) {
// sale has been made write commision entries
// make sure my afid are set
   
if (empty($_SESSION[afid])) {
       
$_SESSION[afid] = getaffiliateforuser($user->uid, false);
       
$_SESSION[afidup] = getaffiliateforuser($user->uid, true);
    }
   
// get total of commissionalbe products
   
$comm_total = 0;
    foreach (
$order->products as $product) {
       
$x = node_load($product->nid);
        if (
$x->type == "supplements")     $comm_total += ($product->price * $product->qty);
    }
    if (
$_SESSION[afid]) {
   
// write primany commission record
       
db_query("insert into {uc_affiliate_pay} (order_id, afid, commission, commission_notes) values ($order->order_id, $_SESSION[afid], $comm_total * .2, '20% commission on $comm_total sale  to $order->billing_first_name $order->billing_last_name')");   
    }
    if (
$_SESSION[afidup]) {
   
// write secondary commission record
           
db_query("insert into {uc_affiliate_pay} (order_id, afid, commission, commission_notes) values ($order->order_id, $_SESSION[afidup], $comm_total * .05, '5% commission on $comm_total sale to $order->billing_first_name $order->billing_last_name')");   

    }
  }
}
?>

actually you can now find

mimetic2 - June 26, 2008 - 01:48

actually you can now find somethign similiar here:

http://www.ubercart.org/contrib/2446

 
 

Drupal is a registered trademark of Dries Buytaert.