=== modified file 'uc_file/uc_file.module'
--- uc_file/uc_file.module	2010-03-29 17:42:00 +0000
+++ uc_file/uc_file.module	2010-03-30 17:40:49 +0000
@@ -718,6 +718,7 @@
   if (!is_dir(variable_get('uc_file_base_dir', NULL))) {
     drupal_set_message(t('A file directory needs to be configured in <a href="!url">product feature settings</a> before a file can be selected.', array('!url' => url('admin/store/settings/products/edit/features'))), 'error');
 
+    unset($form['buttons']);
     return $form;
   }
 
@@ -729,6 +730,7 @@
       ),
     );
 
+    unset($form['buttons']);
     return $form;
   }
 
@@ -767,8 +769,8 @@
   }
 
   $form['nid'] = array(
-      '#type' => 'value',
-      '#value' => $node->nid,
+    '#type' => 'value',
+    '#value' => $node->nid,
   );
   $form['pfid'] = array(
     '#type' => 'value',
@@ -871,7 +873,7 @@
     '#suffix' => '</div>',
   );
 
-  return uc_product_feature_form($form);
+  return $form;
 }
 
 /**
@@ -947,7 +949,7 @@
 
   // Insert or update uc_file_product table
   if (empty($file_product['pfid'])) {
-    $file_product['pfid'] = db_last_insert_id('uc_product_features', 'pfid');
+    $file_product['pfid'] = $data['pfid'];
   }
 
   $key = NULL;

=== modified file 'uc_product/uc_product.admin.inc'
--- uc_product/uc_product.admin.inc	2010-03-24 13:11:48 +0000
+++ uc_product/uc_product.admin.inc	2010-03-30 17:31:09 +0000
@@ -397,107 +397,87 @@
 /**
  * Displays the product features tab on a product node edit form.
  */
-function uc_product_features($node) {
+function uc_product_features($node, $fid = NULL, $pfid = NULL) {
   drupal_set_title($node->title);
 
   $build = array();
-  if (arg(4)) {
-    // First check to see if we're trying to remove a feature.
-    if (intval(arg(5)) > 0 && arg(6) == 'delete') {
-      $result = db_query("SELECT * FROM {uc_product_features} WHERE pfid = :pfid AND fid = :fid", array(
-        ':pfid' => arg(5),
-        ':fid' => arg(4),
-      ));
-      if ($feature = $result->fetchAssoc()) {
-        // If the user confirmed the delete, process it!
-        if ($_POST['pf_delete']) {
-          // Call the delete function for this product feature if it exists.
-          $func = uc_product_feature_data($feature['fid'], 'delete');
-          if (function_exists($func)) {
-            $func($feature);
-          }
-
-          // Remove the product feature data from the database.
-          db_delete('uc_product_features')
-            ->condition('pfid', arg(5))
-            ->execute();
-
-          drupal_set_message(t('The product feature has been deleted.'));
-          drupal_goto('node/' . arg(1) . '/edit/features');
-        }
-
-        // Show the confirmation form for deleting this feature.
-        $question = $node->title;
-        $description = t('Are you sure you wish to delete this %feature?', array('%feature' => uc_product_feature_data($feature['fid'], 'title')))
-                      . '<div><b>' . t('Description') . ':</b><br />' . $feature['description'] . '</div><br />';
-        $form = array();
-        return confirm_form($form, $question, 'node/' . arg(1) . '/edit/features', $description, t('Delete'), t('Cancel'), 'pf_delete');
-      }
-      else {
-        drupal_set_message(t("That product feature doesn't exist."), 'error');
-        drupal_goto('node/' . arg(1) . '/edit/features');
-      }
-    }
-
-    // Handle adding or editing product features.
-    $func = uc_product_feature_data(arg(4), 'callback');
-    if (function_exists($func)) {
-      if (arg(5) == 'add') {
-        $build = drupal_get_form($func, $node, array());
-      }
-      elseif (intval(arg(5)) > 0) {
-        $result = db_query("SELECT * FROM {uc_product_features} WHERE pfid = :pfid AND fid = :fid", array(
-          ':pfid' => arg(5),
-          ':fid' => arg(4),
-        ));
-        if ($feature = $result->fetchAssoc()) {
-          $build = drupal_get_form($func, $node, $feature);
-        }
-      }
-    }
-    else {
-      drupal_set_message(t('Error: Attempted to add a non-existent product feature type.'), 'error');
-      drupal_goto('node/' . $node->nid . '/edit/features');
-    }
-
-    if (empty($build)) {
-      drupal_set_message(t('Error: No form data was returned for that operation.'), 'error');
-      drupal_goto('node/' . $node->nid . '/edit/features');
-    }
-
-    return $build;
-  }
 
   $header = array(t('Type'), t('Description'), t('Operations'));
 
-  $result = db_query("SELECT * FROM {uc_product_features} WHERE nid = :nid ORDER BY pfid ASC", array(':nid' => $node->nid));
-  foreach ($result as $feature) {
-    $operations = array(
-      l(t('edit'), 'node/' . $node->nid . '/edit/features/' . $feature->fid . '/' . $feature->pfid),
-      l(t('delete'), 'node/' . $node->nid . '/edit/features/' . $feature->fid . '/' . $feature->pfid . '/delete'),
-    );
-    $rows[] = array(
-      'data' => array(
-        array('data' => uc_product_feature_data($feature->fid, 'title'), 'nowrap' => 'nowrap'),
-        array('data' => $feature->description, 'width' => '100%'),
-        array('data' => implode(' ', $operations), 'nowrap' => 'nowrap'),
-      ),
-      'valign' => 'top',
-    );
-  }
-
-  if (empty($rows)) {
+  $features = uc_product_feature_load_multiple($node->nid);
+  if (empty($features)) {
     $rows[] = array(
       array('data' => t('No features found for this product.'), 'colspan' => 3),
     );
   }
+  else {
+    foreach ($features as $feature) {
+      $operations = array(
+        l(t('edit'), 'node/'. $node->nid .'/edit/features/'. $feature->fid .'/'. $feature->pfid),
+        l(t('delete'), 'node/'. $node->nid .'/edit/features/'. $feature->fid .'/'. $feature->pfid .'/delete'),
+      );
+      $rows[] = array(
+        'data' => array(
+          array('data' => uc_product_feature_data($feature->fid, 'title'), 'nowrap' => 'nowrap'),
+          array('data' => $feature->description, 'width' => '100%'),
+          array('data' => implode(' ', $operations), 'nowrap' => 'nowrap'),
+        ),
+        'valign' => 'top',
+      );
+    }
+  }
 
   $build['features'] = array(
     '#theme' => 'table',
     '#header' => $header,
     '#rows' => $rows,
   );
-  $build['add_form'] = drupal_get_form('uc_product_feature_add_form');
+  $build['add_form'] = drupal_get_form('uc_product_feature_add_form', $node);
+
+  return $build;
+}
+
+/**
+ * Handle adding or editing product features.
+ */
+function uc_product_feature_edit($node, $fid, $pfid) {
+  $func = uc_product_feature_data($fid, 'callback');
+
+  if (function_exists($func)) {
+    $form_state = array(
+      'build_info' => array(
+        'args' => array(
+          $node,
+        ),
+      ),
+      'wrapper_callback' => 'uc_product_feature_form',
+    );
+
+    if ($pfid == 'add') {
+      $form_state['build_info']['args'][] = array();
+      $build = drupal_build_form($func, $form_state);
+    }
+    elseif (intval($pfid) > 0) {
+      $feature = uc_product_feature_load($pfid);
+
+      if (isset($feature)) {
+        $form_state['build_info']['args'][] = $feature;
+        $build = drupal_build_form($func, $form_state);
+      }
+    }
+    else {
+      drupal_goto('node/' . $node->nid . '/edit/features');
+    }
+  }
+  else {
+    drupal_set_message(t('Error: Attempted to add a non-existent product feature type.'), 'error');
+    drupal_goto('node/' . $node->nid . '/edit/features');
+  }
+
+  if (empty($build)) {
+    drupal_set_message(t('Error: No form data was returned for that operation.'), 'error');
+    drupal_goto('node/' . $node->nid . '/edit/features');
+  }
 
   return $build;
 }
@@ -510,7 +490,7 @@
  *   theme_uc_product_feature_add_form()
  *   uc_product_feature_add_form_submit()
  */
-function uc_product_feature_add_form($form, &$form_state) {
+function uc_product_feature_add_form($form, &$form_state, $node) {
   foreach (module_invoke_all('uc_product_feature') as $feature) {
     $options[$feature['id']] = $feature['title'];
   }
@@ -542,7 +522,39 @@
  * @see uc_product_feature_add_form().
  */
 function uc_product_feature_add_form_submit($form, &$form_state) {
-  $form_state['redirect'] = 'node/' . arg(1) . '/edit/features/' . $form_state['values']['feature'] . '/add';
+  $node = $form_state['build_info']['args'][0];
+
+  $form_state['redirect'] = 'node/' . $node->nid . '/edit/features/' . $form_state['values']['feature'] . '/add';
+}
+
+/**
+ * Confirmation form to delete a product feature.
+ *
+ * @ingroup forms
+ * @see uc_product_feature_confirm_delete_submit()
+ */
+function uc_product_feature_confirm_delete($form, &$form_state, $node, $fid, $feature) {
+  $question = $node->title;
+  $description = t('Are you sure you wish to delete this %feature?', array('%feature' => uc_product_feature_data($fid, 'title')))
+    . '<div><b>' . t('Description') . ':</b><br />' . $feature['description'] . '</div><br />';
+
+  return confirm_form($form, $question, 'node/' . $node->nid . '/edit/features', $description, t('Delete'), t('Cancel'), 'pf_delete');
+}
+
+/**
+ * @see uc_product_feature_confirm_delete()
+ */
+function uc_product_feature_confirm_delete_submit($form, &$form_state) {
+  $node = $form_state['build_info']['args'][0];
+  $feature = $form_state['build_info']['args'][2];
+
+  if ($form_state['values']['pf_delete']) {
+    uc_product_feature_delete($feature['pfid']);
+
+    drupal_set_message(t('The product feature has been deleted.'));
+  }
+
+  $form_state['redirect'] = 'node/' . $node->nid . '/edit/features';
 }
 
 /**

=== modified file 'uc_product/uc_product.module'
--- uc_product/uc_product.module	2010-03-30 15:23:14 +0000
+++ uc_product/uc_product.module	2010-03-30 17:42:33 +0000
@@ -114,6 +114,25 @@
       'type' => MENU_LOCAL_TASK,
       'file' => 'uc_product.admin.inc',
     );
+
+    $items['node/%node/edit/features/%/%'] = array(
+      'page callback' => 'uc_product_feature_edit',
+      'page arguments' => array(1, 4, 5),
+      'access callback' => 'uc_product_feature_access',
+      'access arguments' => array(1),
+      'type' => MENU_CALLBACK,
+      'file' => 'uc_product.admin.inc',
+    );
+
+    $items['node/%node/edit/features/%/%uc_product_feature/delete'] = array(
+      'title' => 'Delete feature',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('uc_product_feature_confirm_delete', 1, 4, 5),
+      'access callback' => 'uc_product_feature_access',
+      'access arguments' => array(1),
+      'type' => MENU_CALLBACK,
+      'file' => 'uc_product.admin.inc',
+    );
   }
 
   $items['admin/store/settings/products/defaults'] = array(
@@ -1931,26 +1950,29 @@
  *     cancel link.
  * @ingroup forms
  */
-function uc_product_feature_form($form) {
-  if (!isset($form['nid'])) {
-    $form['nid'] = array(
-      '#type' => 'hidden',
-      '#value' => intval(arg(1)),
-    );
-  }
-  if (!isset($form['pfid'])) {
+function uc_product_feature_form($form, &$form_state, $node, $feature) {
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid,
+  );
+
+  // Forms to add a feature are only given an empty array.
+  if (!empty($feature)) {
     $form['pfid'] = array(
       '#type' => 'hidden',
-      '#value' => intval(arg(5)),
+      '#value' => $feature['pfid'],
     );
   }
 
-  $form['submit'] = array(
+  $form['buttons'] = array(
+    '#weight' => 20,
+  );
+  $form['buttons']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save feature'),
   );
-  $form['cancel'] = array(
-    '#markup' => l(t('Cancel'), 'node/' . intval(arg(1)) . '/edit/features'),
+  $form['buttons']['cancel'] = array(
+    '#markup' => l(t('Cancel'), 'node/' . $node->nid . '/edit/features'),
   );
 
   return $form;
@@ -1966,32 +1988,19 @@
  *   - fid: the string ID of the feature type
  *   - description: the string description of the feature for the overview table
  */
-function uc_product_feature_save($data) {
-  if (empty($data['nid']) && arg(0) == 'node' && intval(arg(1)) > 0) {
-    $data['nid'] = intval(arg(1));
-  }
-  if (empty($data['pfid'])) {
-    if (arg(0) == 'node' && arg(3) == 'features' && intval(arg(5)) > 0) {
-      $data['pfid'] = intval(arg(5));
-    }
-  }
-
-  // First attempt to update an existing row.
-  $result = db_merge('uc_product_features')
-    ->key(array('pfid' => $data['pfid']))
-    ->fields(array(
-      'nid' => $data['nid'],
-      'fid' => $data['fid'],
-      'description' => $data['description'],
-    ))
-    ->update(array('description' => $data['description']))
-    ->execute();
-
-  // Otherwise insert this feature as a new row.
-  if ($result == MergeQuery::STATUS_INSERT) {
+function uc_product_feature_save(&$data) {
+  $key = NULL;
+
+  if (!empty($data['pfid'])) {
+    $key = 'pfid';
+  }
+
+  $result = drupal_write_record('uc_product_features', $data, $key);
+
+  if ($result == SAVED_NEW) {
     drupal_set_message(t('The product feature has been added.'));
   }
-  else {
+  elseif ($result == SAVED_UPDATED) {
     drupal_set_message(t('The product feature has been updated.'));
   }
 
@@ -1999,6 +2008,61 @@
 }
 
 /**
+ * Load all product feature for a node.
+ *
+ * @param $nid
+ *   The product node ID.
+ * @returns
+ *   The array of all product features object.
+ */
+function uc_product_feature_load_multiple($nid) {
+  $features = db_query("SELECT * FROM {uc_product_features} WHERE nid = :nid ORDER BY pfid ASC", array(':nid' => $nid))->fetchAllAssoc('pfid');
+
+  return $features;
+}
+
+/**
+ * Load a product feature object.
+ *
+ * @todo: should return an object instead of array.
+ *
+ * @param $pfid
+ *   The product feature ID.
+ * @param $fid
+ *   Optional. Specify a specific feature id.
+ * @returns
+ *   The product feature array.
+ */
+function uc_product_feature_load($pfid) {
+  $feature = db_query("SELECT * FROM {uc_product_features} WHERE pfid = :pfid", array(':pfid' => $pfid))->fetchAssoc();
+
+  return $feature;
+}
+
+/**
+ * Delete a product feature object.
+ *
+ * @param $pfid
+ *   The product feature ID.
+ * @returns
+ *   The product feature object.
+ */
+function uc_product_feature_delete($pfid) {
+  $feature = uc_product_feature_load($pfid);
+
+  // Call the delete function for this product feature if it exists.
+  $func = uc_product_feature_data($feature['fid'], 'delete');
+  if (function_exists($func)) {
+    $func($feature);
+  }
+  db_delete('uc_product_features')
+    ->condition('pfid', $pfid)
+    ->execute();
+
+  return SAVED_DELETED;
+}
+
+/**
  * Create a file field with an image field widget, and attach it to products.
  *
  * This field is used by default on the product page, as well as on the cart

=== modified file 'uc_roles/uc_roles.module'
--- uc_roles/uc_roles.module	2010-03-29 17:42:00 +0000
+++ uc_roles/uc_roles.module	2010-03-30 17:36:20 +0000
@@ -677,6 +677,9 @@
 
   $roles = _uc_roles_get_choices();
   if (!count($roles)) {
+    // No actions can be done. Remove submit buttons.
+    unset($form['buttons']);
+
     $form['no_roles'] = array(
       '#markup' => t('You need to <a href="!url">create new roles</a> before any can be added as product features.', array('!url' => url('admin/people/permissions/roles', array('query' => array('destination' => 'admin/store/settings/products/edit/features'))))),
       '#prefix' => '<p>',
@@ -766,7 +769,7 @@
     '#description' => t('Check if the role duration should be multiplied by the quantity purchased.'),
   );
 
-  return uc_product_feature_form($form);
+  return $form;
 }
 
 /**
@@ -799,7 +802,7 @@
   }
 
   // This role already set on this SKU?
-  if ($form_state['values']['pfid'] == 0 && ($product_roles = db_query("SELECT * FROM {uc_roles_products} WHERE nid = :nid AND model = :model AND rid = :rid", array(':nid' => $form_state['values']['nid'], ':model' => $form_state['values']['uc_roles_model'], ':rid' => $form_state['values']['uc_roles_role']))->fetchObject())) {
+  if (!isset($form_state['values']['pfid']) && ($product_roles = db_query("SELECT * FROM {uc_roles_products} WHERE nid = :nid AND model = :model AND rid = :rid", array(':nid' => $form_state['values']['nid'], ':model' => $form_state['values']['uc_roles_model'], ':rid' => $form_state['values']['uc_roles_role']))->fetchObject())) {
     form_set_error('uc_roles_role', t('The combination of SKU and role already exists for this product.'));
     form_set_error('uc_roles_model', ' ');
   }
@@ -826,8 +829,8 @@
  */
 function uc_roles_feature_form_submit($form, &$form_state) {
   $product_role = array(
-    'pfid'        => $form_state['values']['pfid'],
-    'rpid'        => $form_state['values']['rpid'],
+    'pfid'        => isset($form_state['values']['pfid']) ? $form_state['values']['pfid'] : NULL,
+    'rpid'        => isset($form_state['values']['rpid']) ? $form_state['values']['rpid'] : NULL,
     'nid'         => $form_state['values']['nid'],
     'model'       => $form_state['values']['uc_roles_model'],
     'rid'         => $form_state['values']['uc_roles_role'],
@@ -887,7 +890,7 @@
 
   // Insert or update uc_file_product table
   if (empty($product_role['pfid'])) {
-    $product_role['pfid'] = db_last_insert_id('uc_product_features', 'pfid');
+    $product_role['pfid'] = $data['pfid'];
   }
 
   uc_roles_product_write_record($product_role);

