diff --git a/geofield.widgets.openlayers.inc b/geofield.widgets.openlayers.inc
index c95ed49..47ea775 100644
--- a/geofield.widgets.openlayers.inc
+++ b/geofield.widgets.openlayers.inc
@@ -59,17 +59,68 @@ function openlayers_field_widget_settings_form($field, $instance) {
     ),
     '#default_value' => (isset($settings['data_storage'])) ? $settings['data_storage'] : 'collection',
   );
+
+  // Add optional Geocoder support.
+  $use_geocoder = isset($settings['use_geocoder']) ? $settings['use_geocoder'] : 0;
+  $geocoder_form = array(
+    '#type' => 'fieldset',
+    '#title' => t('Geocoder settings'),
+  );
+  if (module_exists('geocoder')) {
+    $geocoder_form['use_geocoder'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable geocoding of location data (best when used with an address field)'),
+      '#default_value' => $use_geocoder,
+    );
+    // Load the Geocoder widget settings.
+    module_load_include('inc', 'geocoder', 'geocoder.widget');
+    $new = geocoder_field_widget_settings_form($field, $instance);
+    // Show the geocoder fields only if geocoder is selected.
+    openlayers_widget_add_states($new, ':input[name="instance[widget][settings][use_geocoder]"]');
+
+    $geocoder_form += $new;
+  }
+  else {
+    $geocoder_form['add_geocoder'] = array(
+      '#markup' => t('Optionally, install the <a href="http//drupal.org/project/geocoder">Geocoder</a> module and add an <a href="http://drupal.org/project/addressfield">Address field</a> to enable mapping by address.'),
+    );
+  }
+  $form += $geocoder_form;
+
   return $form;
 }
 
 /**
+ * Recurse through form elements adding a visibility #states selector
+ * and removing #required flags.
+ */
+function openlayers_widget_add_states(&$element, $selector) {
+  foreach (element_children($element) as $key) {
+    $element[$key]['#required'] = FALSE;
+    // Don't override any existing #states settings.
+    if (!isset($element[$key]['#states'])) {
+      $element[$key]['#states'] = array();
+    }
+    if (!isset($element[$key]['#states']['visible'])) {
+      $element[$key]['#states']['visible'] = array();
+    }
+    $element[$key]['#states']['visible'][$selector] = array('checked' => TRUE);
+    openlayers_widget_add_states($element[$key], $selector);
+  }
+}
+
+/**
  * Implements hook_field_widget_form().
  */
 function openlayers_field_widget_form(&$form, &$form_state, $field, $instance,
   $langcode, $items, $delta, $base) {
 
+  $parents = $form['#parents'];
+  $field_name = $field['field_name'];
   $widget = $instance['widget'];
   $settings = $widget['settings'];
+  $id_prefix = implode('-', array_merge($parents, array($field_name)));
+  $wrapper_id = drupal_html_id($id_prefix . '-use-geocoder-wrapper');
   $element = geofield_get_base_element($base, $items, $delta);
 
   $geo_value = $element['wkt']['#value'];
@@ -86,6 +137,41 @@ function openlayers_field_widget_form(&$form, &$form_state, $field, $instance,
   $element['#openlayers_mapname'] = $openlayers_map_id;
   $element['#after_build']= array('openlayers_geofield_widget_afterbuild');
 
+  // Conditionally add geocoder button.
+  if (!empty($settings['use_geocoder']) && !empty($settings['geocoder_field'])) {
+    if ($field = field_info_instance($instance['entity_type'], $settings['geocoder_field'], $instance['bundle'])) {
+      $label = $field['label'];
+    }
+    else {
+      switch ($settings['geocoder_field']) {
+        case 'title':
+          $label = t('Title');
+          break;
+        case 'name':
+          $label = t('Name');
+          break;
+        default:
+          $label = $settings['geocoder_field'];
+      }
+    }
+    $element['#prefix'] = '<div id="' . $wrapper_id . '">';
+    $element['#suffix'] = '</div>';
+
+    $element['use_geocoder'] = array(
+      '#type' => 'submit',
+      '#name' => strtr($id_prefix, '-', '_') . '_use_geocoder',
+      '#value' => t('Geocode from @field field', array('@field' => $label)),
+      '#attributes' => array('class' => array('field-use-geocoder-submit')),
+      '#limit_validation_errors' => array(array_merge($parents, array($field_name, $langcode)), array($settings['geocoder_field'], $langcode)),
+      '#ajax' => array(
+        'callback' => 'openlayers_widget_geocode',
+        'wrapper' => $wrapper_id,
+        'effect' => 'fade',
+      ),
+      '#submit' => array('openlayers_use_geocoder_submit'),
+    );
+  }
+
   // This validate function computes all other columns from the master field
   $element['#element_validate'] = array('geofield_element_validate');
   $element['#data_storage'] = (!empty($settings['data_storage'])) ? $settings['data_storage'] : 'collection';
@@ -94,6 +180,46 @@ function openlayers_field_widget_form(&$form, &$form_state, $field, $instance,
 }
 
 /**
+ * Submit callback for widget form.
+ */
+function openlayers_use_geocoder_submit($form, &$form_state) {
+  $button = $form_state['triggering_element'];
+  // Go one level up in the form, to the widgets container.
+  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
+  $field_name = $element['#field_name'];
+  $langcode = $element['#language'];
+  $delta = $element['#delta'];
+  $parents = $element['#field_parents'];
+
+  // Set the widget value based on geocoding results.
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+  $entity = clone($element['#entity']);
+  $geocoder_field = $field_state['instance']['widget']['settings']['geocoder_field'];
+  $entity->$geocoder_field = $form_state['values'][$geocoder_field];
+  if ($field_value = geocoder_widget_get_field_value($element['#entity_type'], $entity, $field_state['instance'])) {
+    $field_value[$langcode][$delta]['widget'] = $field_value[$langcode][$delta]['wkt'];
+    drupal_array_set_nested_value($form_state, array_merge(array('input'), $parents, array($field_name)), $field_value);
+  }
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Return changed form.
+ *
+ * @see openlayers_field_widget_form()
+ */
+function openlayers_widget_geocode($form, $form_state) {
+  $button = $form_state['triggering_element'];
+  // Go one level up in the form, to the widgets container.
+  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
+  $field_name = $element['#field_name'];
+  // Return the full field. It will replace itself via the wrapper div ID set
+  // in the element's #prefix.
+  return $form[$field_name];
+}
+
+/**
  * Callback for afterbuild for widget for js addition to
  */
 
