
diff -urp old/ubercart/uc_attribute/uc_attribute.module new/ubercart/uc_attribute/uc_attribute.module
--- old/ubercart/uc_attribute/uc_attribute.module	2008-06-18 14:25:32.296875000 +0300
+++ new/ubercart/uc_attribute/uc_attribute.module	2008-06-18 12:57:31.093750000 +0300
@@ -3,8 +3,6 @@
 
 /**
  * @file
- * Übercart Attribute module.
- *
  * Allows customers to buy slightly different products from the same listing.
  *
  * Many manufacturers provide options to their products. This module provides a way
@@ -367,16 +365,26 @@ function uc_attribute_admin() {
 
   $result = pager_query("SELECT a.*, COUNT(ao.oid) AS options FROM {uc_attributes} AS a LEFT JOIN {uc_attribute_options} AS ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.ordering". tablesort_sql($header), 30);
   while ($attr = db_fetch_object($result)) {
+    $attribute = uc_attribute_load($attr->aid);
+    if ($attribute->dynamic) {
+       $options = NULL;
+       $options_num = t('Dynamic options');
+    }
+    else {
+      $options = l(t('options'), 'admin/store/products/attributes/'. $attr->aid .'/options');
+      $options_num = $attr->options;  
+    }
+    
     $ops = array(
-      l(t('edit'), 'admin/store/products/attributes/'. $attr->aid .'/edit'),
-      l(t('options'), 'admin/store/products/attributes/'. $attr->aid .'/options'),
-      l(t('delete'), 'admin/store/products/attributes/'. $attr->aid .'/delete'),
+      'edit' => l(t('edit'), 'admin/store/products/attributes/'. $attr->aid .'/edit'),
+      'options' => $options,
+      'delete' => l(t('delete'), 'admin/store/products/attributes/'. $attr->aid .'/delete'),
     );
     $rows[] = array(
       $attr->name,
       $attr->required == 1 ? t('Yes') : t('No'),
       array('data' => $attr->ordering, 'align' => 'center'),
-      array('data' => $attr->options, 'align' => 'center'),
+      array('data' => $options_num, 'align' => 'center'),
       $display_types[$attr->display],
       implode(' ', $ops),
     );
@@ -403,7 +411,9 @@ function uc_attribute_admin() {
  */
 function uc_attribute_form($aid = NULL) {
   // If an attribute ID is specified, load it and add its ID as a hidden value.
-  $attribute = uc_attribute_load($aid);
+  if ($aid) {
+    $attribute = uc_attribute_load($aid);
+  }
 
   if (!empty($attribute)) {
     $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
@@ -517,10 +527,13 @@ function uc_attribute_options($aid) {
   $header = array(t('Name'), t('Default cost'), t('Default price'), t('Default weight'), t('Order'), t('Operations'));
 
   foreach ($attribute->options as $key => $data) {
-    $ops = array(
-      l(t('edit'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/edit'),
-      l(t('delete'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/delete'),
-    );
+    $ops = array(t('Disabled - dynamic options'));
+    if (!$attribute->dynamic) {
+      $ops = array(
+        l(t('edit'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/edit'),
+        l(t('delete'), 'admin/store/products/attributes/'. $aid .'/options/'. $key .'/delete'),
+      );
+    }
     $rows[] = array($data->name, $data->cost, $data->price, $data->weight, $data->ordering, implode(' ', $ops));
   }
   if (count($rows) == 0) {
@@ -564,55 +577,61 @@ function uc_attribute_option_form($aid, 
   else {
     drupal_set_title(t('Options for %name', array('%name' => $attribute->name)));
   }
-
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Name'),
-    '#description' => t('This name will appear to customers on product add to cart forms.'),
-    '#default_value' => $option->name,
-    '#required' => TRUE,
-    '#weight' => 0,
-  );
-  $form['ordering'] = array(
-    '#type' => 'weight',
-    '#title' => t('Order'),
-    '#description' => t('Options will be listed sorted by this value and then by their name.<br />May be overridden at the product level.'),
-    '#default_value' => $option->ordering,
-    '#weight' => 4,
-  );
-  $form['adjustments'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Default adjustments'),
-    '#description' => t('Enter a positive or negative value for each adjustment applied when this option is selected.<br />Any of these may be overriden at the product level.'),
-    '#collapsible' => FALSE,
-    '#weight' => 8,
-  );
-  $form['adjustments']['cost'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Cost'),
-    '#default_value' => $option->cost,
-    '#weight' => 1,
-  );
-  $form['adjustments']['price'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Price'),
-    '#default_value' => $option->price,
-    '#weight' => 2,
-  );
-  $form['adjustments']['weight'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Weight'),
-    '#default_value' => $option->weight,
-    '#weight' => 3,
-  );
-
-  $form['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Submit'),
-    '#suffix' => l(t('Cancel'), 'admin/store/products/attributes/'. $aid .'/options'),
-    '#weight' => 10,
-  );
-
+  if (!$attribute->dynamic) {
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#description' => t('This name will appear to customers on product add to cart forms.'),
+      '#default_value' => $option->name,
+      '#required' => TRUE,
+      '#weight' => 0,
+    );
+    $form['ordering'] = array(
+      '#type' => 'weight',
+      '#title' => t('Order'),
+      '#description' => t('Options will be listed sorted by this value and then by their name.<br />May be overridden at the product level.'),
+      '#default_value' => $option->ordering,
+      '#weight' => 4,
+    );
+    $form['adjustments'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Default adjustments'),
+      '#description' => t('Enter a positive or negative value for each adjustment applied when this option is selected.<br />Any of these may be overriden at the product level.'),
+      '#collapsible' => FALSE,
+      '#weight' => 8,
+    );
+    $form['adjustments']['cost'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Cost'),
+      '#default_value' => $option->cost,
+      '#weight' => 1,
+    );
+    $form['adjustments']['price'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Price'),
+      '#default_value' => $option->price,
+      '#weight' => 2,
+    );
+    $form['adjustments']['weight'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Weight'),
+      '#default_value' => $option->weight,
+      '#weight' => 3,
+    );
+  
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Submit'),
+      '#suffix' => l(t('Cancel'), 'admin/store/products/attributes/'. $aid .'/options'),
+      '#weight' => 10,
+    );
+  }
+  else {
+    $form['dynamic'] = array(
+     '#type' => 'item',
+     '#value' => t('The attribute is dynamic, therefore you can\'t add or edit options. If you have other options already enabled they will be disregarded.')
+    );
+  }
   return $form;
 }
 
@@ -1296,7 +1315,7 @@ function uc_attribute_load($attr_id, $ni
         $attribute = db_fetch_object(db_query("SELECT * FROM {uc_attributes} WHERE aid = %d", $attr_id));
         $result = db_query("SELECT * FROM {uc_attribute_options} WHERE aid = %d ORDER BY ordering, name", $attr_id);
         break;
-    }
+    }
     if (isset($attribute->default_ordering) && is_null($attribute->ordering)) {
       $attribute->ordering = $attribute->default_ordering;
     }
@@ -1312,12 +1331,15 @@ function uc_attribute_load($attr_id, $ni
     $result = db_query("SELECT * FROM {uc_attribute_options} WHERE aid = %d ORDER BY ordering, name", $attr_id);
   }
   if ($attribute) {
+    // By default attirbues have static options.
+    $attribute->dynamic = FALSE;
     $attribute->options = array();
     while ($option = db_fetch_object($result)) {
       $attribute->options[$option->oid] = $option;
     }
-  }
-
+  }
+  // Allow other modules to list their data into the attribute list.
+  module_invoke_all('uc_attribute', 'list', $attribute);
   return $attribute;
 }
 
@@ -1325,6 +1347,11 @@ function uc_attribute_load($attr_id, $ni
 function uc_attribute_option_load($oid) {
   return db_fetch_object(db_query("SELECT * FROM {uc_attribute_options} WHERE oid = %d", $oid));
 }
+
+function uc_attribute_option_update($option) {
+  module_invoke_all('uc_option', 'load', $option);
+  return $option;
+}
 
 // Loads all attributes associated with a product node.
 function uc_product_get_attributes($nid) {
@@ -1348,7 +1375,17 @@ function uc_class_get_attributes($pcid) 
   }
 
   return $attributes;
-}
+}
+
+/**
+ * Load more data to an option object.
+ * 
+ * @param $option
+ *  The option object.
+ * @return
+ *  The option object with additional data, if added by other modules.
+ */
+ 
 
 /**
  * Display formatted of data associated with attributes
@@ -1430,7 +1467,10 @@ function _uc_cart_product_get_options($i
       // Only discrete options can affect the price of an item.
       if ($attribute->display && count($attribute->options)) {
         $options[$aid] = (array)$attribute->options[$oid];
-        $options[$aid]['attribute'] = $attribute->name;
+        $options[$aid]['attribute'] = $attribute->name;
+        // options_key_url will be used to create a link from the order pane.
+        //TODO: Don't load options if dynamic is TRUE.
+        !empty($attribute->dynamic) ? $options[$aid]['options_key_url'] = $attribute->options_key_url : $options[$aid]['options_key_url']='';
       }
       else {
         $options[$aid] = array('attribute' => $attribute->name,
@@ -1438,7 +1478,8 @@ function _uc_cart_product_get_options($i
           'name' => check_plain($oid),
           'cost' => 0,
           'price' => 0,
-          'weight' => 0,
+          'weight' => 0,
+          'options_key_url'=> '/admin/store/products/attributes/'. $attribute->aid .'/options/',
         );
       }
     }
diff -urp old/ubercart/uc_order/uc_order.module new/ubercart/uc_order/uc_order.module
--- old/ubercart/uc_order/uc_order.module	2008-06-18 14:25:56.343750000 +0300
+++ new/ubercart/uc_order/uc_order.module	2008-06-18 14:23:18.937500000 +0300
@@ -2544,9 +2544,13 @@ function uc_order_save($order) {
         $attributes = array();
         $options = _uc_cart_product_get_options($product);
         foreach ($options as $aid => $option) {
-          $attributes[$option['attribute']] = $option['name'];
+          $attributes[$option['attribute']] = $option['name'];
+	        // Keep the option object.
+	        $product->data['options'][$option['oid']] = $option;          
         }
-        $product->data['attributes'] = $attributes;
+
+        $product->data['attributes'] = $attributes;
+
       }
       uc_order_product_save($order->order_id, $product);
     }
Only in new/ubercart/uc_order: uc_order_line_item.inc
diff -urp old/ubercart/uc_order/uc_order_order_pane.inc new/ubercart/uc_order/uc_order_order_pane.inc
--- old/ubercart/uc_order/uc_order_order_pane.inc	2008-06-18 14:25:50.765625000 +0300
+++ new/ubercart/uc_order/uc_order_order_pane.inc	2008-06-18 12:57:36.500000000 +0300
@@ -685,11 +685,17 @@ function op_products_view_table($op, $pr
       if (is_array($products)) {
         foreach ($products as $product) {
           $data['qty'][] = array('data' => $product->qty .'x', 'align' => 'right');
-          $options = $product->data['attributes'];
+          $options = $product->data['options'];
           $option_rows = array();
           if (module_exists('uc_attribute') && is_array($options)) {
-            foreach ($options as $attribute => $option) {
-              $option_rows[] = t('@attribute: @option', array('@attribute' => $attribute, '@option' => $option));
+            foreach ($options as $attribute => $option) {
+              $option = (object)$option;
+              // Allow other modules to load their data into the option object.
+              uc_attribute_option_update($option);
+              // Set the option link according to options key URL.
+              $option->dynamic ? $option_key = $option->options_key_url : $option_key =  'admin/store/products/attributes/'. $attribute .'/options/%/edit';
+              $option_key_link = str_replace('%', $option->oid, $option_key);
+              $option_rows[] = t('@attribute: !option', array('@attribute' => $option->attribute, '!option' => l($option->name, $option_key_link)));
             }
           }
           $data['product'][] = check_plain($product->title) . theme('item_list', $option_rows, NULL, 'ul', array('class' => 'product-options'));
