9

My setup is:

  1. Addressfield on nodes to collect address data
  2. Geofield using "Geocode from another field" choosing the addressfield and the Google Geocoder

When I edit/save a node in the UI, the data is geocoded. However, I have thousands of nodes and am trying to write a script to update the geocode info on each node.

I tried loading all the nodes and doing a node_save() but the geocode hooks didn't fire.

How can I programmatically update the geofield information? Is there a hook I can use?

4

According to README.TXT:

API NOTES

Geofield fields contain nine columns of information about the geographic > data that is stores. At its heart is the 'wkt' column where it stores the full geometry in the 'Well Known Text' (WKT) format. All other columns are metadata derived from the WKT column. Columns are as follows:

'geom' Raw value. By default, stored as WKB, loaded as WKT
'geo_type' Type of geometry (point, linestring, polygon etc.)
'lat' Centroid (Latitude or Y)
'lon' Centroid (Longitude or X)
'top' Bounding Box Top (Latitude or Max Y) 'bottom' Bounding Box Bottom (Latitude or Min Y)
'left' Bounding Box Left (Longitude or Min X)
'right' Bounding Box Right (Longitude or Max X)
'geohash' Geohash equivalent of geom column value

When a geofield is saved using the provided widgets, these values are passed through the geofield_compute_values function in order to compute dependent values. By default dependent values are computed based on WKT, but this may be overriden to compute values based on other columns. For example, geofield_compute_values may be called like so:

geofield_compute_values($values, 'latlon');

This will compute the wkt field (and all other fields) based on the lat/lon columns, resulting in a point. As a developer this is important to remember if you modify geofield information using node_load and node_save. Make sure to run any modified geofield instances through geofield_compute_values in order to make all columns consistent.

This translates to:

      $spot->field_coordinates[LANGUAGE_NONE][0] = geofield_compute_values(
          array(
              'lat' => $venue->location->lat, 
              'lon' => $venue->location->lng,
      ), GEOFIELD_INPUT_LAT_LON);
2

Using values like this, I was able to update a geofield's data programatically:

PHP

$lat = 42.281646;
$lon = -83.744222;
$geofield = array(
  'geom' => "POINT ($lon $lat)",
  'geo_type' => 'point',
  'lat' => $lat . "000000",
  'lon' => $lon . "000000",
  'left' => $lon . "000000",
  'top' => $lat . "000000",
  'right' => $lon . "000000",
  'bottom' => $lat . "000000"
);
$lang = $node->language;
$node->field_position[$lang][0] = $geofield;

JSON for Services Module

{
  "nid":123,
  "field_position":{"und":[
    {"geom":{"lat":"42.2808256","lon":"-83.7430378"}}
  ]}
}

In both cases, the widget for the geofield is Latitude / Longitude, so results may vary for other widgets, especially with the Services module.

  • Does this update the geohash? – beroe Feb 22 at 1:01
  • I don't know what you mean by geohash, please confirm, thanks. – tyler.frankenstein Feb 22 at 4:02
  • Hi. Sorry for the cryptic comment. Drupal's node__field_geo_field has a geohash as its last field (see API in the answer above). That is an ascii representation of a geographic region. I don't know if they are mandatory or optional, but I was going to make a python program to generate them and insert (along with lat/long) into the backend drupal database. – beroe Feb 22 at 7:06
  • Thanks for confirming. I myself am unfamiliar with the geohash value, but perhaps you can use the geofield_compute_values function mentioned in the answer above to get that value from the lat/lng. – tyler.frankenstein Feb 22 at 14:28
1

A wild guess: You may run your node through the node-edit-form process to get the geofield-magic fired.

Have a look at drupal_form_submit(), observe the $form_state['values'] from an ordinary, manual submission of your node type's "add content" form and rebuild them programmatically to send it in the drupal_form_submit() function.

I wonder if that would work...

On the other hand, you could just inspect the structure of your geofield's value and rebuild that programmatically leveraging the geocoder() function of the geocoder module's API.

0

You can use the method described in https://www.drupal.org/node/905814#comment-4931016.

  1. Take a database backup

  2. Make a view of your content. Add a filter to select the content where the geofield latitude is empty.

  3. Add the Views Bulk Operations module, add a bulk operations field and choose as action "execute arbitrary php".

    $test = node_load($entity->nid);    
    module_load_include('inc', 'node', 'node.pages');    
    $test_state['values']['op'] = t('Save');    
    drupal_form_submit('NODENAME_node_form', $test_state, $test);
    

This approach works perfectly except that Date fields that are using the date popup display become empty, so be careful if you have date fields.

Also notice that the Google geocoder has a 24h limit of 2500 addresses to geocode.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.