Index: uc_affiliate2.module
===================================================================
--- uc_affiliate2.module	(revision 439)
+++ uc_affiliate2.module	(working copy)
@@ -347,7 +347,7 @@
     }
 
     $product->path = (!$product->path) ? 'node/'. $product->nid : $product->path;
-    $link = $GLOBALS['base_url'] .'/'. variable_get('uc_affiliate2_path', 'affiliate') .'/'. $user->uid .'/'. $product->path;
+    $link = _uc_affiliate2_generate_link('default', $product->path, $user);
 
     if (empty($product->field_image_cache[0]['filepath'])) {
       $image = 'N/A';
@@ -939,6 +939,78 @@
 }
 
 /**
+ * Generate an affiliate link.
+ *
+ * The $type can be 'path', 'query', or 'subdomain'. An additional value,
+ * 'default', is also supported, which just uses whatever the default is.
+ *
+ * To generate a <a> tag (such as with the l() function), set a 'text'
+ * option equal to the text inside the tag, and a 'url' option equal to
+ * FALSE.
+ *
+ * To generate only a url (such as with the url() function), set a 'url'
+ * option equal to TRUE. This option is true by default if there is no
+ * 'text' option.
+ *
+ * See l() (if the url option is FALSE) or url() for other options.
+ */
+function _uc_affiliate2_generate_link($type, $path, $user, $options = array()) {
+  if ($type == 'default') {
+    $type = variable_get('affiliate_default_link_type', 'path');
+  }
+
+  // Merge in defaults.
+  $options += array(
+    'url' => empty($options['text']),
+    'text' => NULL,
+  );
+
+  // Affiliate links are always absolute.
+  $options['absolute'] = TRUE;
+
+  // Subdomain links don't work with all usernames.
+  if ($type == 'subdomain' && !preg_match('/^[A-Z0-9\-]{1,63}$/i', $user->name)) {
+    $type = 'path';
+  }
+
+  switch ($type) {
+    case 'path':
+      $path = variable_get('uc_affiliate2_path', 'affiliate') . '/' . $user->uid . $path;
+      break;
+    case 'query':
+      if (isset($options['query']) && !is_array($options['query'])) {
+        if (strlen($options['query'])) {
+          $options['query'] .= '&';
+        }
+        $options['query'] .= "a=" . $user->uid;
+      }
+      else {
+        $options['query']['a'] = $user->uid;
+      }
+      break;
+    case 'subdomain':
+      // A base_url option isn't really supposed to be passed into url(),
+      // since the docs say it's only used internally, but it does work
+      // so we're about to use it. Also allow the caller of this function
+      // to send it as well.
+      if (!isset($options['base_url'])) {
+        $options['base_url'] = $GLOBALS['base_url'];
+      }
+      // I am uncomfortable not using the count parameter, but it's not available
+      // before php5, and there really shouldn't be extra ://'s in there.
+      $options['base_url'] = str_replace('://', '://' . strtolower($user->name) . '.', $options['base_url']);
+      break;
+  }
+
+  if ($options['url']) {
+    return url($path, $options);
+  }
+  else {
+    return l($options['text'], $path, $options);
+  }
+}
+
+/**
  * Extract the subdomain from the host variable
  */
 function _uc_affiliate2_get_subdomain() {
Index: uc_affiliate2.user.inc
===================================================================
--- uc_affiliate2.user.inc	(revision 439)
+++ uc_affiliate2.user.inc	(working copy)
@@ -108,18 +108,29 @@
   $output .= '</div>';
 
   $output .= '<br /><div id="affiliate-links-header"><h2>' . t('Affiliate Links') . '</h2>';
-  $output .= t('You can append a destination page to the end of the affiliate links to redirect to a specific page,
-              as well as track clicks to it, i.e.
-              example.com/!path/!uid/node/1', array('!uid' => $user->uid, '!path' => variable_get('uc_affiliate2_path', 'affiliate'))) . '<br /> <br />';
+  switch (variable_get('affiliate_default_link_type', 'path')) {
+    case 'path':
+      $output .= t('You can append a destination page to the end of the affiliate links to redirect to a specific page,
+                  as well as track clicks to it, i.e.
+                  example.com/@path/@uid/node/1', array('@uid' => $user->uid, '@path' => variable_get('uc_affiliate2_path', 'affiliate')));
+      break;
+    case 'query':
+      $output .= t('You can link to any page on this site by adding your query argument (?a=@uid) to the end of the url, i.e. example.com/node/1?a=@uid', array('@uid' => $user->uid));
+      break;
+    case 'subdomain':
+      $output .= t('You can turn any link on this site into an affiliate link using your subdomain, i.e. @subdomain.example.com/node/1', array('@subdomain' => $user->name));
+      break;
+  }
 
   $text_link = variable_get('affiliate_text_link_template', '');
-  $text_link = l($text_link, variable_get('uc_affiliate2_path', 'affiliate'). '/'. $user->uid, array('query' => NULL, 'fragment' => NULL, 'absolute' => TRUE, 'html' => TRUE));
-  $output .= '<b>' . t('Text Link:') . '</b> <br /> <textarea cols="45">'. $text_link .'</textarea>';
+  $text_link = _uc_affiliate2_generate_link('default', NULL, $user, array('text' => $text_link, 'html' => TRUE));
+  $text_link = array('#type' => 'textarea', '#title' => t('Text Link'), '#value' => $text_link);
+  $output .= drupal_render($text_link);
 
   $output .= _uc_affiliate2_display_banners();
 
   $links_url = join('/', array('user', $user->uid, 'affiliate', 'links'));
-  $output .= '<br />' . l(t('Click here for product links.'), $links_url, array('query' => NULL, 'fragment' => NULL, 'absolute' => TRUE, 'html' => TRUE));
+  $output .= '<p>' . l(t('Click here for product links.'), $links_url, array('query' => NULL, 'fragment' => NULL, 'absolute' => TRUE, 'html' => TRUE)) . '</p>';
 
   $output .= '</div>';
 
@@ -276,7 +287,7 @@
 
   foreach ($banners as $banner) {
     $banner = '<'. $banner;
-    $banner_link = l($banner, variable_get('uc_affiliate2_path', 'affiliate') .'/'. $user->uid, array('query' => NULL, 'fragment' => NULL, 'absolute' => TRUE, 'html' => TRUE));
+    $banner_link = _uc_affiliate2_generate_link('default', NULL, $user, array('text' => $banner, 'html' => TRUE));
 
     $line = array();
     $line[] = $banner;
Index: uc_affiliate2.admin.inc
===================================================================
--- uc_affiliate2.admin.inc	(revision 439)
+++ uc_affiliate2.admin.inc	(working copy)
@@ -332,6 +332,16 @@
     '#description' => t("If enabled, this module will record affiliate actions if customers visit the site through an affiliate subdomain, like john.thissite.com. Enable this only if drupal is not installed on a subdomain."),
     '#default_value' => variable_get('affiliate_enable_subdomain_handling', 0),
   );
+  $form['affiliate_default_link_type'] = array(
+    '#type' => 'radios',
+    '#title' => t('Default affiliate link type'),
+    '#options' => array(
+      'path' => t('Use a special path (!example)', array('!example' => 'http://example.com/<strong>' . check_plain(variable_get('uc_affiliate2_path', 'affiliate')) . '/123</strong>')),
+      'query' => t('Use a query argument (!example)', array('!example' => 'http://example.com/<strong>?a=123</strong>')),
+      'subdomain' => t('Use a subdomain (!example)', array('!example' => 'http://<strong>username.</strong>example.com/')),
+    ),
+    '#default_value' => variable_get('affiliate_default_link_type', 'path'),
+  );
   $form['affiliate_subsequent_order_commissions'] = array(
     '#type' => 'radios',
     '#title' => t('Affiliate commissions for future orders placed by users they referred'),
@@ -381,6 +391,10 @@
   if (!empty($url) && ($url != check_url($url) || strpos($url, '://') !== FALSE)) {
     form_set_error('affiliate_invalid_redirect', t('Please enter a valid Drupal path, without the http and domain parts.'));
   }
+
+  if (empty($form_state['values']['affiliate_enable_subdomain_handling']) && $form_state['values']['affiliate_default_link_type'] == 'subdomain') {
+    form_set_error('affiliate_default_link_type', t('The default link type is set to use a subdomain, but subdomain handling is disabled.'));
+  }
 }
 
 /**
