The attached patch creates a new display formatter, "Geocode from another field with option to manually select coordinates." On the field settings page, you can select from any of the geofield formatters (Lat/Lon, WKT, HTML5, etc). When displaying the field widget on the entity edit page, there will be a little checkbox, "Manually select fields". Checking the field will display the appropriate widget fields.

Caveats/things to fix:

  • Only works with geofield module (no support for location or other modules because I didn't need it).
  • Only supports single-delta fields. If you have multiple deltas it will break.
  • If the Manual checkbox is checked, the geofield "source" value will be "manual". This was the easiest way to store this data without having to alter the table structure. Not sure if this will break compatibility with some of the formatters or break some standards.

Tested with a node and a user with an addressfield and geofield with Lat/Lon selected as the manual entry.

Comments

rudetrue’s picture

I've applied this patch and it looks great, however when I go to the edit page, and check the Manual Entry box, the incorrect widget is attempting to display, but is blank. I want to make this work with the Leaflet Widget for Geofield module. That way the user can check the box and use the map to set the marker. Any help would be appreciated!

I've went through the code but am not sure what is missing/incorrect. The hooks all seem correct when I read the documentation..

rudetrue’s picture

StatusFileSize
new9.67 KB

I've attached a screenshot of the issue. The field is an address, maybe that's why it keeps trying to show that widget rather than the one I choose in the dropdown?

Anonymous’s picture

+1 for this patch. It's awesome.

nurulshakina’s picture

Issue summary: View changes

this patch is awesome. Great job! However, i am getting this error after applied the patch.

"Notice: Undefined offset: 0 in geocoder_field_attach_presave() (line 229 of C:\xampp\htdocs\examplesites\sites\all\modules\geocoder\geocoder.widget.inc)"

i am really appreciate if anyone could help me with this. thanks

adel-by’s picture

First, thanks for this patch.
i made a module out of your code that fits my needs.
changed the way you pass "source" to the hook_field_attach_presave i'm using drupal_static in stead.
this fixes the notice in #4

here's the module :

/**
 * Implements hook_field_widget_info().
 */
function geocoder_plus_field_widget_info() {
  return array(
      'geocoder_manual' => array(
      'label' => t('Geocode from another field with option to manually enter lat/lon'),
      'field types' => array('geofield'),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
      ),
    ),
  );
}

function geocoder_plus_field_widget_settings_form($this_field, $instance) {
  $settings = $instance['widget']['settings'];
  module_load_include('inc', 'geocoder', 'geocoder.widget');
  $form = geocoder_field_widget_settings_form($this_field, $instance);
  
    // Add the manual method select.
  if (module_exists('geofield') && $instance['widget']['type'] == 'geocoder_manual') {
    $options = array();
    foreach (geofield_field_widget_info() as $key => $info) {
      $options[$key] = $info['label'];
    }
    $form['manual_widget'] = array(
      '#type' => 'select',
      '#title' => t('Wiget to use for manually entry'),
      '#default_value' => isset($settings['manual_widget']) ? $settings['manual_widget']: 'geofield_latlon',
      '#options' => $options,
      '#required' => TRUE,
    );
  }
  
  return $form;
}

/**
 * Implements hook_field_widget_form().
 */
function geocoder_plus_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
  // We only need to output something if the manual option is selected
  if ($instance['widget']['type'] == 'geocoder_manual') {
    $element = array();
    
    // Add the manual checkbox
    $element['geocoder_manual']['#title'] = 'Manually enter coordinates';
    $element['geocoder_manual']['#type'] = 'checkbox';
    $element['geocoder_manual']['#weight'] = -100;
    $element['geocoder_manual']['#default_value'] = (bool) (!empty($items['0']['lat']));

    // Add the manual fields from geofield.
    $instance['widget']['type'] = $instance['widget']['settings']['manual_widget'];
    $element['geocoder_manual_fieldset'] = geofield_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $base);
    $element['geocoder_manual_fieldset']['#type'] = 'fieldset';
    $element['geocoder_manual_fieldset']['#states'] = array(
      'invisible' => array(
        ':input[name="' . $instance['field_name'] . '[und][geocoder_manual]"]' => array('checked' => FALSE),
      ),
    );
    $instance['widget']['type'] = 'geocoder_manual';

    // Add a custom validate callback to move the geocoder_manual field into
    // the geofield source attribute
    $element['#element_validate'] = array('geocoder_plus_manual_field_element_validate');

    // Allow this element form array to be altered.
    drupal_alter('field_geocoder_manual_widget', $element, $form, $instance);

    return $element;
  }
}

/**
 * Field validate function to move the geocoder_manual field into the
 * geofield source attribute
 */
function geocoder_plus_manual_field_element_validate(&$element, &$form_state) {
  // store the source manual or geocode ia a static var so we can catch it later
  $static_source = &drupal_static(__FUNCTION__);
  $static_source[$element['#field_name']] = $form_state['values'][$element['#field_name']][LANGUAGE_NONE]['geocoder_manual'] ? 'manual' : NULL;
}

/**
 * Implements hook_field_attach_presave().
 *
 * Geocoding for the geocoder widget is done here to ensure that only validated
 * and fully processed fields values are accessed.
 */
function geocoder_plus_field_attach_presave($entity_type, $entity) {
  // Loop over any geofield using our geocode widget
  $entity_info = entity_get_info($entity_type);
  $bundle_name = empty($entity_info['entity keys']['bundle']) ? $entity_type : $entity->{$entity_info['entity keys']['bundle']};
  $static_source = drupal_static('geocoder_plus_manual_field_element_validate');
  foreach (field_info_instances($entity_type, $bundle_name) as $field_instance) {
    if ($field_instance['widget']['type'] === 'geocoder_manual' && $static_source[$field_instance['field_name']] != 'manual') {
      if (($field_value = geocoder_widget_get_field_value($entity_type, $field_instance, $entity)) !== FALSE) {
        $entity->{$field_instance['field_name']} = $field_value;
      }
    }
  }
}
mtoscano’s picture

This feature it is very interesting and a step forward to fix possible geocoding errors, thanks.
I installed the module but nothing happens. I mean I expect to see an additional widget to use for manually entry, am I missing something?
Any help it is really appreciated.

nurulshakina’s picture

Hi,

Thanks, #5 really helps me. I managed to get work perfectly using localhost on my laptop. However, when I tried to deploy on the server, the browser went blank. It was so horrifying. I checked on my log my file it tells me that 'call time pass by reference has been removed by geocoder.widget.inc on line 185'. Is it possible it happened because of PHP version?

I managed to run #5 module smoothly on the server. THANKS CHIKIPI! Bless you!

Regards

iaminawe’s picture

I get the same result as @mato - I make a nodule out of the code in #5, enable it, clear caches and dont see any change to the geofield field?
Am I looking in the correct place. Any insight would b helpful.

Thanks

iaminawe’s picture

The module solution did not work for me but the patch worked correctly after removing the & symbols from geocoder.widget.inc on line 185 - and I can leave out the address and correct a point by manually entering in the long/lat value- Thanks for this!

fietserwin’s picture

If you make a module out of it:
- Name the module geocoder_plus, ie. create files geocoder_plus.info and geocoder_plus.module.
- geocoder_plus.info should contain:

name = Geocoder plus field
description = An widget on top of the geocoder widget that adds a manual entry fallback widget.
core = 7.x
dependencies[] = geocoder
dependencies[] = geofield

- geocoder_plus.module should contain the above code.
- Enable the module.
- Go to your content type,tab manage fields: admin/structure/types/manage/{your-content-type}/fields.
- Change the field widget of the geofield to "Geocode from another field with option to manually enter lat/lon".
- In the field (widget) settings, select the "Widget to use for manually entry" and save the settings.

You're done.

rafalenden’s picture

I think this functionality is "must have" and should be included in Geocoder module itself.

simon georges’s picture

Does the patch works properly? Patch applies cleanly on current -dev version, so it could be integrated rather quickly if it is the case.

kenfordesign’s picture

I have created a new custom module with #5. Works as expected. Thanks!

joelpittet’s picture

StatusFileSize
new4.64 KB
new3.99 KB

Here's an update of the patch in #0

There was a call time by reference failure, a typo some coding standards fixes and a some other fixes.

joelpittet’s picture

Status: Needs review » Needs work
StatusFileSize
new29.64 KB
new773 bytes
new4.52 KB

Minor notice variable didn't exist.

Also my patch above wasn't relative, sorry.

Here's a screenshot but there is an issue with double wrapping fieldset at the moment.

joelpittet’s picture

Status: Needs work » Needs review
StatusFileSize
new1.24 KB
new4.52 KB

Ah that's easy to fix, just use container type;)

Anyways I think this patch may need a bit of love and clean-up but it seems to do the trick in a quick test run.

joelpittet’s picture

Status: Needs review » Needs work
  1. +++ b/geocoder.widget.inc
    @@ -13,6 +13,14 @@ function geocoder_field_widget_info() {
    +        'default value' => FIELD_BEHAVIOR_NONE,
    

    Was this meant to be commented out in the original patch?

  2. +++ b/geocoder.widget.inc
    @@ -138,10 +146,69 @@ function geocoder_field_widget_settings_form($this_field, $instance) {
    +  if (module_exists('geofield') && $instance['widget']['type'] == 'geocoder_manual') {
    +    module_load_include('inc', 'geofield', 'geofield.widgets');
    

    This is pretty cool, I wonder if it's possible to just do this with all the field types and put it on the regular geocoder widget?

  3. +++ b/geocoder.widget.inc
    @@ -138,10 +146,69 @@ function geocoder_field_widget_settings_form($this_field, $instance) {
    +    $element['geocoder_manual']['#default_value'] = (bool) (isset($items[0]['source']) && $items[0]['source'] == 'manual');
    

    This feels a bit sketchy...

  4. +++ b/geocoder.widget.inc
    @@ -138,10 +146,69 @@ function geocoder_field_widget_settings_form($this_field, $instance) {
    +    $element['geocoder_manual_fieldset'] = geofield_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $base);
    

    There must be a better way to get the field definition?

Manual checkbox disappeared after the first save and there was a warning about not being able to loop through element_children()...

mtoscano’s picture

The HTML5 geolocation is included in the Lat/Lon widget (bad idea BTW), but if I select the Lat/Lon widget and the fallback option the HTML5 option is not there.
So it is impossible to have the HTML5 gelocation as the fallback option.

joelpittet’s picture

@mato Want to try your hand at pushing this patch forward a bit?

pol’s picture

Status: Needs work » Closed (outdated)