--- link.install
+++ link.install
@@ -32,6 +32,18 @@
         'type' => 'text',
         'size' => 'medium',
         'not null' => FALSE
+      ),
+      'prefix' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'sortable' => TRUE
+      ),
+      'suffix' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'sortable' => TRUE
       ),
     ),
   );
@@ -116,3 +128,33 @@
     }
   }
 }
+
+/**
+ * Adds columns for prefix and suffix
+ */
+function link_update_7002() {
+	$result = db_query("SELECT id, field_name, data FROM {field_config} WHERE module = 'link' AND type = 'link_field'");
+  foreach ($result as $field) {
+  	$field_id = $field->id;
+    $name = $field->field_name;
+    
+    $data = unserialize($field->data);
+    $data['storage']['details']['sql']['FIELD_LOAD_CURRENT']['field_data_field_link']['prefix'] = 'field_link_prefix';
+    $data['storage']['details']['sql']['FIELD_LOAD_CURRENT']['field_data_field_link']['suffix'] = 'field_link_suffix';
+    $data['storage']['details']['sql']['FIELD_LOAD_REVISION']['field_revision_field_link']['prefix'] = 'field_link_prefix';
+    $data['storage']['details']['sql']['FIELD_LOAD_REVISION']['field_revision_field_link']['suffix'] = 'field_link_suffix';
+    
+    $data_update = db_update('field_config')
+          ->fields(array('data' => serialize($data)))
+          ->condition('id', $field_id)
+          ->execute();
+    
+    db_query("ALTER TABLE `field_data_".$name."` 
+    	ADD `".$name."_prefix` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
+    	ADD `".$name."_suffix` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL");
+    	
+    db_query("ALTER TABLE `field_revision_".$name."` 
+    	ADD `".$name."_prefix` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
+    	ADD `".$name."_suffix` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL");
+  }
+}
--- link.module
+++ link.module
@@ -36,6 +36,12 @@
         'title' => 'optional',
         'title_value' => '',
         'title_maxlength' => 128, //patch #1307788 from nmc
+        'prefix' => 'optional',
+        'prefix_value' => '',
+        'prefix_maxlength' => 128,
+        'suffix' => 'optional',
+        'suffix_value' => '',
+        'suffix_maxlength' => 128,
         'enable_tokens' => 1,
         'display' => array(
           'url_cutoff' => 80,
@@ -47,6 +53,12 @@
         'title' => 'optional',
         'title_value' => '',
         'title_maxlength' => 128, // patch #1307788 from nmc
+        'prefix' => 'optional',
+        'prefix_value' => '',
+        'prefix_maxlength' => 128,
+        'suffix' => 'optional',
+        'suffix_value' => '',
+        'suffix_maxlength' => 128,
         'enable_tokens' => 1,
         'display' => array(
           'url_cutoff' => 80,
@@ -112,6 +124,68 @@
     '#title' => t('Max length of title field'),
     '#default_value' => isset($instance['settings']['title_maxlength']) ? $instance['settings']['title_maxlength'] : '128',
     '#description' => t('Set a maximum length on the title field (applies only if Link Title is optional or required).  The maximum limit is 255 characters.'),
+    '#maxlength' => 3,
+    '#size' => 3,
+    );
+
+  $prefix_options = array(
+    'optional' => t('Optional Prefix'),
+    'required' => t('Required Prefix'),
+    'value' => t('Static Prefix'),
+    'none' => t('No Prefix'),
+  );
+
+  $form['prefix'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Prefix'),
+    '#default_value' => isset($instance['settings']['prefix']) ? $instance['settings']['prefix'] : 'optional',
+    '#options' => $prefix_options,
+    '#description' => t('If the link prefix is optional or required, a field will be displayed to the end user. If the link prefix is static, the link will always use the same prefix. If <a href="http://drupal.org/project/token">token module</a> is installed, the static prefix value may use any other node field as its value. Static and token-based prefixes may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+  );
+
+  $form['prefix_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Static prefix'),
+    '#default_value' => isset($instance['settings']['prefix_value']) ? $instance['settings']['prefix_value'] : '',
+    '#description' => t('This prefix will always be used if &ldquo;Static Prefix&rdquo; is selected above.'),
+  );
+
+  $form['prefix_maxlength'] = array( // patch #1307788 from nmc
+    '#type' => 'textfield',
+    '#title' => t('Max length of prefix field'),
+    '#default_value' => isset($instance['settings']['prefix_maxlength']) ? $instance['settings']['prefix_maxlength'] : '128',
+    '#description' => t('Set a maximum length on the prefix field (applies only if Link Prefix is optional or required).  The maximum limit is 255 characters.'),
+    '#maxlength' => 3,
+    '#size' => 3,
+    );
+
+  $suffix_options = array(
+    'optional' => t('Optional Suffix'),
+    'required' => t('Required Suffix'),
+    'value' => t('Static Suffix'),
+    'none' => t('No Suffix'),
+  );
+
+  $form['suffix'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Suffix'),
+    '#default_value' => isset($instance['settings']['suffix']) ? $instance['settings']['suffix'] : 'optional',
+    '#options' => $suffix_options,
+    '#description' => t('If the link suffix is optional or required, a field will be displayed to the end user. If the link suffix is static, the link will always use the same suffix. If <a href="http://drupal.org/project/token">token module</a> is installed, the static suffix value may use any other node field as its value. Static and token-based suffixes may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+  );
+
+  $form['suffix_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Static suffix'),
+    '#default_value' => isset($instance['settings']['suffix_value']) ? $instance['settings']['suffix_value'] : '',
+    '#description' => t('This suffix will always be used if &ldquo;Static Suffix&rdquo; is selected above.'),
+  );
+
+  $form['suffix_maxlength'] = array( // patch #1307788 from nmc
+    '#type' => 'textfield',
+    '#title' => t('Max length of suffix field'),
+    '#default_value' => isset($instance['settings']['suffix_maxlength']) ? $instance['settings']['suffix_maxlength'] : '128',
+    '#description' => t('Set a maximum length on the suffix field (applies only if Link Suffix is optional or required).  The maximum limit is 255 characters.'),
     '#maxlength' => 3,
     '#size' => 3,
     );
@@ -212,6 +286,14 @@
       && empty($form_state['values']['instance']['settings']['title_value'])) {
     form_set_error('title_value', t('A default title must be provided if the title is a static value.'));
   }
+	if ($form_state['values']['instance']['settings']['prefix'] === 'value'
+      && empty($form_state['values']['instance']['settings']['prefix_value'])) {
+    form_set_error('prefix_value', t('A default prefix must be provided if the prefix is a static value.'));
+  }
+	if ($form_state['values']['instance']['settings']['suffix'] === 'value'
+      && empty($form_state['values']['instance']['settings']['suffix_value'])) {
+    form_set_error('suffix_value', t('A default suffix must be provided if the suffix is a static value.'));
+  }
   if (!empty($form_state['values']['instance']['settings']['display']['url_cutoff'])  // patch #1307788 from nmc
       && !is_numeric($form_state['values']['instance']['settings']['display']['url_cutoff'])) {
     form_set_error('display', t('URL Display Cutoff value must be numeric.'));
@@ -333,7 +415,7 @@
   if (empty($item['attributes'])) {
     $item['attributes'] = array();
   }
-
+  
   // Serialize the attributes array.
   if (!is_string($item['attributes'])) {
     $item['attributes'] = serialize($item['attributes']);
@@ -364,6 +446,14 @@
     if ($instance['settings']['title'] == 'required' && strlen(trim($item['title'])) == 0) {
       form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
     }
+    // Require a prefix for the link if necessary.
+    if ($instance['settings']['prefix'] == 'required' && strlen(trim($item['prefix'])) == 0) {
+    	form_set_error($field['field_name'] .']['. $delta .'][prefix', t('Prefixes are required for all links.'));
+    }
+    // Require a suffix for the link if necessary.
+    if ($instance['settings']['suffix'] == 'required' && strlen(trim($item['suffix'])) == 0) {
+    	form_set_error($field['field_name'] .']['. $delta .'][suffix', t('Suffixes are required for all links.'));
+    }
   }
   // Require a link if we have a title.
   if ($instance['settings']['url'] !== 'optional'
@@ -473,6 +563,50 @@
     $item['html'] = TRUE;
   }
   $item['title'] = empty($title) ? $item['display_url'] : $title;
+  
+  // Use the prefix defined at the instance level.
+  if ($instance['settings']['prefix'] == 'value' && strlen(trim($instance['settings']['prefix_value']))) {
+  	$prefix = $instance['settings']['prefix_value'];
+  }
+  // Use the prefix defined by the user at the widget level.
+  else if (isset($item['prefix'])) {
+  	$prefix = $item['prefix'];
+  }
+  else {
+  	$prefix = '';
+  }
+  
+  // Replace tokens.
+  if ($prefix && ($instance['settings']['prefix'] == 'value' || $instance['settings']['enable_tokens'])) {
+  	// Load the node if necessary for nodes in views.
+  	$token_node = isset($node->nid) ? node_load($node->nid) : $node;
+  	$prefix = filter_xss(token_replace($prefix, array('node' => $token_node)),
+  			array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+  	$item['html'] = TRUE;
+  }
+  $item['prefix'] = empty($prefix) ? '' : $prefix;
+
+  // Use the suffix defined at the instance level.
+  if ($instance['settings']['suffix'] == 'value' && strlen(trim($instance['settings']['suffix_value']))) {
+  	$suffix = $instance['settings']['suffix_value'];
+  }
+  // Use the suffix defined by the user at the widget level.
+  else if (isset($item['suffix'])) {
+  	$suffix = $item['suffix'];
+  }
+  else {
+  	$suffix = '';
+  }
+  
+  // Replace tokens.
+  if ($suffix && ($instance['settings']['suffix'] == 'value' || $instance['settings']['enable_tokens'])) {
+  	// Load the node if necessary for nodes in views.
+  	$token_node = isset($node->nid) ? node_load($node->nid) : $node;
+  	$suffix = filter_xss(token_replace($suffix, array('node' => $token_node)),
+  			array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+  	$item['html'] = TRUE;
+  }
+  $item['suffix'] = empty($suffix) ? '' : $suffix;
 
   if (!isset($item['attributes'])) {
     $item['attributes'] = array();
@@ -554,6 +688,12 @@
     'link_formatter_link_title_plain' => array(
       'variables' => array('element' => NULL),
     ),
+    'link_formatter_link_prefix_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_suffix_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
     'link_formatter_link_url' => array(
       'variables' => array('element' => NULL),
     ),
@@ -588,10 +728,16 @@
 
   $output = '';
   $output .= '<div class="link-field-subrow clearfix">';
+	if (isset($element['prefix'])) {
+    $output .= '<div class="link-field-prefix link-field-column">'. drupal_render($element['prefix']) .'</div>';
+  }
   if (isset($element['title'])) {
     $output .= '<div class="link-field-title link-field-column">'. drupal_render($element['title']) .'</div>';
   }
-  $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. drupal_render($element['url']) .'</div>';
+  if (isset($element['suffix'])) {
+  	$output .= '<div class="link-field-suffix link-field-column">'. drupal_render($element['suffix']) .'</div>';
+  }
+  $output .= '<div class="link-field-url'. (isset($element['prefix']) || isset($element['suffix']) || isset($element['title']) ? ' link-field-column' : '') .'">'. drupal_render($element['url']) .'</div>';
   $output .= '</div>';
   if (!empty($element['attributes']['target'])) {
     $output .= '<div class="link-attributes">'. drupal_render($element['attributes']['target']) .'</div>';
@@ -651,6 +797,26 @@
       '#required' => ($settings['title'] == 'required' && (($element['#delta'] == 0 && $element['#required']) || !empty($element['#value']['url']))) ? TRUE : FALSE, // davereids patch from jan 2011
       '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
     );
+  }
+  if ($settings['prefix'] !== 'none' && $settings['prefix'] !== 'value') {
+  	$element['prefix'] = array(
+  			'#type' => 'textfield',
+  			'#maxlength' => $settings['prefix_maxlength'],
+  			'#title' => t('Prefix'),
+  			'#description' => t('The link prefix is limited to '.$settings['prefix_maxlength'].' characters maximum.'),
+  			'#required' => ($settings['prefix'] == 'required' && (($element['#delta'] == 0 && $element['#required']) || !empty($element['#value']['url']))) ? TRUE : FALSE,
+  			'#default_value' => isset($element['#value']['prefix']) ? $element['#value']['prefix'] : NULL,
+  	);
+  }
+  if ($settings['suffix'] !== 'none' && $settings['suffix'] !== 'value') {
+  	$element['suffix'] = array(
+  			'#type' => 'textfield',
+  			'#maxlength' => $settings['suffix_maxlength'],
+  			'#title' => t('Suffix'),
+  			'#description' => t('The link suffix is limited to '.$settings['suffix_maxlength'].' characters maximum.'),
+  			'#required' => ($settings['suffix'] == 'required' && (($element['#delta'] == 0 && $element['#required']) || !empty($element['#value']['url']))) ? TRUE : FALSE,
+  			'#default_value' => isset($element['#value']['suffix']) ? $element['#value']['suffix'] : NULL,
+  	);
   }
 
   // Initialize field attributes as an array if it is not an array yet.
@@ -725,6 +891,16 @@
       'field types' => array('link_field'),
       'multiple values' => FIELD_BEHAVIOR_DEFAULT,
     ),
+    'link_prefix_plain' => array(
+      'label' => t('Prefix, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_suffix_plain' => array(
+      'label' => t('Suffix, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
   );
 }
 
@@ -756,14 +932,14 @@
   
   // Display a normal link if both title and URL are available.
   if (!empty($vars['element']['title']) && !empty($vars['element']['url'])) {
-    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+    return (!empty($vars['element']['prefix']) ? $vars['element']['prefix'] : '').l($vars['element']['title'], $vars['element']['url'], $link_options).(!empty($vars['element']['suffix']) ? $vars['element']['suffix'] : '');
   }
   // If only a title, display the title.
   elseif (!empty($vars['element']['title'])) {
-    return check_plain($vars['element']['title']);
+    return (!empty($vars['element']['prefix']) ? $vars['element']['prefix'] : '').check_plain($vars['element']['title']).(!empty($vars['element']['suffix']) ? $vars['element']['suffix'] : '');
   }
   elseif (!empty($vars['element']['url'])) {
-    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+    return (!empty($vars['element']['prefix']) ? $vars['element']['prefix'] : '').l($vars['element']['title'], $vars['element']['url'], $link_options).(!empty($vars['element']['suffix']) ? $vars['element']['suffix'] : '');
   }
 }
 
@@ -786,6 +962,20 @@
   return empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
 }
 
+/**
+ * Theme function for 'prefix_plain' text field formatter.
+ */
+function theme_link_formatter_link_prefix_plain($vars) {
+	return empty($vars['element']['prefix']) ? '' : check_plain($vars['element']['prefix']);
+}
+
+/**
+ * Theme function for 'suffix_plain' text field formatter.
+ */
+function theme_link_formatter_link_suffix_plain($vars) {
+	return empty($vars['element']['suffix']) ? '' : check_plain($vars['element']['suffix']);
+}
+
 /**
  * Theme function for 'url' text field formatter.
  */
@@ -827,6 +1017,8 @@
   unset($link_options['element']['title']);
   unset($link_options['element']['url']);
   $title = empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
+  $prefix = empty($vars['element']['prefix']) ? '' : check_plain($vars['element']['prefix']);
+  $suffix = empty($vars['element']['suffix']) ? '' : check_plain($vars['element']['suffix']);
   
   /** 
    * @TODO static html markup looks not very elegant to me (who takes it off?)
@@ -834,8 +1026,14 @@
    */
   $output = '';
   $output .= '<div class="link-item '. $class .'">';
+	if (!empty($prefix)) {
+    $output .= '<div class="link-prefix">'. $prefix .'</div>';
+  }
   if (!empty($title)) {
     $output .= '<div class="link-title">'. $title .'</div>';
+  }
+	if (!empty($suffix)) {
+    $output .= '<div class="link-suffix">'. $suffix .'</div>';
   }
   $output .= '<div class="link-url">'. l($vars['element']['url'], $vars['element']['url'], $link_options) .'</div>';
   $output .= '</div>';
@@ -850,6 +1048,8 @@
     $tokens['link']['url'] = t("Link URL");
     $tokens['link']['title'] = t("Link title");
     $tokens['link']['view'] = t("Formatted html link");
+    $tokens['link']['prefix'] = t("Link prefix");
+    $tokens['link']['suffix'] = t("Link suffix");
 
     return $tokens;
   }
@@ -862,6 +1062,8 @@
     $tokens['url'] = $item['url'];
     $tokens['title'] = $item['title'];
     $tokens['view'] = isset($item['view']) ? $item['view'] : '';
+    $tokens['prefix'] = $item['prefix'];
+    $tokens['suffix'] = $item['suffix'];
 
     return $tokens;
   }
@@ -1075,6 +1277,14 @@
   if ($instance['settings']['title'] == 'none') {
     unset($property['property info']['title']);
   }
+  $property['property info']['prefix']['required'] = ($instance['settings']['prefix'] == 'required');
+  if ($instance['settings']['prefix'] == 'none') {
+    unset($property['property info']['prefix']);
+  }
+  $property['property info']['suffix']['required'] = ($instance['settings']['suffix'] == 'required');
+  if ($instance['settings']['suffix'] == 'none') {
+    unset($property['property info']['suffix']);
+  }
 
   unset($property['query callback']);
 }
@@ -1102,5 +1312,16 @@
     'label' => t('The URL of the link.'),
     'setter callback' => 'entity_property_verbatim_set',
   );
+  $properties['prefix'] = array(
+  		'type' => 'text',
+  		'label' => t('The prefix of the link.'),
+  		'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['suffix'] = array(
+  		'type' => 'text',
+  		'label' => t('The suffix of the link.'),
+  		'setter callback' => 'entity_property_verbatim_set',
+  );
+  
   return $properties;
 }