Using Ubercart to sell files: ui improvements and creating file feature programmatically

uc_file module that allows selling files in Ubercart is definitely not perfect in terms of API, but it is a nice piece of functionality.
We’ve just finished creating one e-book store which has product-import feature.
Each product has multiple formats (pdf, epub, rtf) - some products can have pdf+epub, some can have just pdf, others have all three formats attached.

On product page, we wanted to show nice block like this:

Ubercart file downloads

where pdf and doc are just text for regular users, and download links for users that already bought this book.

All the code was created for Drupal 7 + Ubercart 7.x-3.x

Creating file feature programmatically

Let’s start from

Creating ubercart product node

= 'My test product';
$price = 100;
$sku = 'testSKU';
$descr = 'Product description is here';

$node = new StdClass();
$node->type = 'product';
$node->language = LANGUAGE_NONE;

$node->title = $title;

// Set Ubercart variables
$node->model = $sku; // the SKU is a required field, so I generated a SKU based on the node title
$node->list_price = $price;
$node->cost = $price;
$node->sell_price = $price;

// populate some required ubercart fields
foreach (array('width', 'height', 'length', 'weight', 'weight_units', 'length_units', 'shippable') as $attr) {
$node->{$attr} = 0;

// get rid of "The quantity cannot be zero." errors 
foreach (array('pkg_qty', 'default_qty') as $attr) {
$node->{$attr} = 1;

$node->body[LANGUAGE_NONE][0]['value'] = $descr; // set body field



Attaching file feature

Now we have $node object ready for adding files.
Make sure that uc_file module is enabled, and you’ve configured directory for files, and put files there (by uploading to ftp/sftp)

Here is the code:

= $node->model; // in my case, filename = product sku + extension
$exts = array('zip', 'pdf'); // the code below expects that there are files testSKU.pdf and in my ubercart files directory

uc_file_refresh(); // copy files from file system to ubercart files table in database

foreach ($exts as $ext) {
$ext = trim($ext);
$fullname = $filename . '.' . $ext;
$file = uc_file_get_by_name($fullname);
    if (!empty(
$file)) {
$existing_file = db_query("SELECT fpid FROM {uc_file_products} WHERE
        fid=:fid AND model=:sku"
, array(':fid' => $file->fid, ':sku' => $product->model))->fetchField();
      if (!
$existing_file) {
$feature = array(
'nid' => $product->nid,
'fid' => 'file',
'description' => $product->title,
drupal_write_record('uc_product_features', $feature);
$file_product = array(
'fid' => $file->fid,
'pfid' => $feature['pfid'],
'filename' => $file->filename,
'model' => $product->model,
'shippable' => $product->shippable,

drupal_write_record('uc_file_products', $file_product);

That’s it!

Now put these two pieces of code together to your module and you should get product with attached files.

Showing available formats and downloadable list of files on product node

It’s surprising that Ubercart doesn’t have such functionality in core - the only interface it has for user is a separate page with complete list of all downloads available for him on the website.

In my project, I just put the code below to _preprocess_node with some conditions (like if ($variables[‘node’]->type == ‘product’ && $variables[‘page’])

and then in node—product.tpl.php I write

echo $files_table;

Here is the code:

= $variables['node']; // that looks like this because the code was used
// in preprocess function - feel free to replace by other node loading code
$variables['files_table'] = _uc_file_user_downloads_by_sku($GLOBALS['user'], $node->model);
// user doesn't have available downloads, get plain text list of extensions
if (!$variables['files_table']) {
// get files list for product
$files = db_query("SELECT f.filename FROM {uc_file_products} p INNER JOIN {uc_files} f ON p.fid=f.fid WHERE p.model = :sku", array(':sku' => $node->model))->fetchCol();
      foreach (
$files as &$file) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
$file = '<span class="' . $ext . '">'. $ext .'</span>';
$variables['files_table'] = '<div class="available-files">'.theme('item_list', array('items' => $files, 'title' => t('File formats available for download'))).'</div>';

// Function inspired by code in uc_file.module
function _uc_file_user_downloads_by_sku($account, $sku) {
$files = db_query(
"SELECT u.granted, f.filename, u.accessed, u.addresses, p.description, u.file_key, f.fid, u.download_limit, u.address_limit, u.expiration FROM {uc_file_users} as u ".
"LEFT JOIN {uc_files} as f ON u.fid = f.fid ".
"LEFT JOIN {uc_file_products} as p ON p.pfid = u.pfid WHERE uid = :uid AND p.model=:sku", array(':uid' => $account->uid, ':sku' => $sku)

$rows = array();
  foreach (
$files as $file) {

$row = count($rows);
$download_limit = $file->download_limit;

// Set the JS behavior when this link gets clicked.
$onclick = array(
'attributes' => array(
'onclick' => 'uc_file_update_download('. $row .', '. $file->accessed .', '. ((empty($download_limit)) ? -1 : $download_limit) .');', 'id' => 'link-'. $row
$ext = pathinfo($file->filename, PATHINFO_EXTENSION);
// Expiration set to 'never'
if ($file->expiration == FALSE) {
$file_link = '<span class="'. $ext .'">' . l($ext, 'download/'. $file->fid .'/'. $file->file_key, $onclick) . '</span>';

// Expired.
elseif (time() > $file->expiration) {
$file_link = $ext;

// Able to be downloaded.
else {
$file_link = '<span class="'. $ext .'">' . l($ext, 'download/'. $file->fid .'/'. $file->file_key, $onclick) . '</span>' .' ('. t('expires on @date', array('@date' => format_date($file->expiration, 'custom', variable_get('uc_date_format_default', 'm/d/Y')))) .')';

$rows[] = $file_link;    
  if (!empty(
$rows)) {
$output = theme('item_list', array('title' => t('Files available for download'), 'items' => $rows));
$output .= '<div class="form-item"><p class="description">'.
t('Once your download is finished, you must refresh the page to download again. (Provided you have permission)') .  
  } else {

Forgive me that the code is a bit ugly, it can (and needs to!) be refactored and improved.

May be someone is interested in such functionality as module? Tell me by leaving a comment, I will be glad to create a module if it will be useful for someone.


nice, that's was something I was looking for, I still have to try it, than i'll let you know how it works.

11 January, 2012


Just wondering if I could grab this write up for a tutorial section on my Ubercart promo site. I'd give you full credit and link back to this site. I'm also looking for developers who are familiar with Ubercart for the Dev For Hire section on my site.

end user

08 February, 2012

Hi! yes, you can :)

02 March, 2012

I could not resist commenting. Perfectly written!

15 June, 2014

I need to import product features into Ubercart via the node import module.

23 October, 2012

Helo Anton Sidashin

Of course this code would very useful for many people by creating a module.

Maybe it can be also integrated with feeds_import module.

11 February, 2013

This would be awesome as a module. The current Ubercart file-selling functionality is pretty atrocious - it makes things have to happen from within two separate interfaces, and is utterly useless except for a one-seller-one-site paradigm. I'm working on a site where the idea is that multiple people would be able to upload and sell their own e-books.

Even if you don't create a module (which there is seriously a need for!) the above code should be enough to let a developer hack together their own implementation.

Thanks so much! I thought I was going to have to go through the Ubercart code line-by-line, in the absence of friendly documentation.

06 June, 2013

Hello it's me, I am also visiting this website regularly, this
website is truly good and the people are in fact sharing good thoughts.

21 October, 2014

Thank you very much :-)

27 October, 2016

Custom Essay Writing Service for College Students
Custom college essay writing task is mandatory for students because it counts to the final grade. The work of custom essay writing is to prepare students in achieving their academic careers. Writing academic essays such as term papers, case studies, review essays, speech papers, research papers and thesis consumes time and resources. With the increase in the number of academic writing services, students should be keen with college custom essay writing service. There are genuine writing companies and there are those writing companies which are in the market to write essay papers that are not original. Best custom writings stand one of the best writing companies which have original custom essays for sale services.
Best custom essay writing service has qualified freelance essay writers who will prepare for you quality custom essays for sale. Best writing assistance have broad scope of writing skills which help to complete your writings as per expected. The custom essays here are prepared by qualified team of writers who have been trained on how to complete custom college papers such as term papers, thesis papers, and speech essays among others. If you want fast and reliable custom essays for sale, visit best custom writing company and make inquiry on how to do the essay orders. If you choose the best, writers here will provide you with premium writings which are delivered with instructions on how you are required to submit your work to the target audience. If you seek help from the online services you can engage your time with other works and you no need to bother with your writings. On time you will receive high quality paper from writers.

14 November, 2016

Willing to buy organic bedding sale? So don't wait!! We are here.

22 November, 2016

Post new comment

Private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

Note for potential spammers: all links in your comment will not be indexed by search engines.

Anton Sidashin

Anton Sidashin senior developer, Pixeljets co-founder

I'm a web developer specializing in PHP and Javascript, and Drupal, of course. I'm building Drupal projects since 2005, and I was working as full-time senior engineer in CS-Cart for a while, building revolutionary e-commerce software. In my free time, I enjoy playing soccer, building my body in gym, and playing guitar. ID: restyler
Drupal association member