Enable Distance Filtering in Drupal Services

When developing mobile apps, location is one of core components that nearly all mobile apps are developed with.  However, when it comes to building mobile apps with Drupal, working with location can be challenging.  There are number of geo-related modules and discussions on enabling location by working with Views.  But in our case, we decided not to use Views, but just with the Services modules, to provide the maximum performance to mobile apps.

So in this post, I will show you how we enabled distance filtering/sorting in Drupal so that the XML/JSON data you get through Services module is filtered or sorted based on locations or latitude/longitude data.

For this, we used following tools/modules:

  • Postgresql database
  • PostGIS extension
  • Services module
  • AddressField module
  • Geocoder & Geofield modules

Postgresql – we use Postgresql instead of MySQL because working with locations is much easier and faster by using PostGIS extension.  Yes, it “is” possible to enable locations with MySQL, but for this exercise, we will use Postgresql and PostGIS combination.

1. Install PostGIS extension

There are numerous websites and pages that show you how to install the PostGIS extension so I won’t cover that here.

2. Install Services, AddressField, Geocoder, Geofield modules

These are all standard Drupal contributed modules that are fairly stable.  If you’ve been using Drupal, then these modules should be familiar to you.  If not, you can easily install them using drush:

drush en services -y
drush en addressfield -y
drush en geocoder -y
drush en geofield -y

3. Create a new field for storing address

Now that we have everything installed, we will go ahead and create a new content type and field to store location information.

We will create a new content type called “Business” and two fields: Address (postal address) and Geodata (geofield) for storing location information such as Well Known Byte (WKB), latitude and longigude. You have to set up Geodata field as “automatically encode from another field” and choose the address field.

Location modules in Drupal

Now, if we look at the database table that holds the field_geodata information, there are three columns that we are interested in and will be using for our exercise: field_geodata_geom, field_geodata_lat, and field_geodata_lon.

Underlying table for Geofield

Your table at this point would be empty. I took above screenshot after adding some sample businesses.

4. Create a custom REST endpoint

For our purpose, we will be exporting businesses from a Drupal site to XML/JSON using the Services module which will be consumed by client apps such as mobile applications. We will create one index function that will retrieve all businesses.

First, create your own module. Then, create a custom REST endpoint using using MODULE_services_resources() to create your own endpoint.  I called my module “isaac”:


function isaac_services_resources() {
  $api = array(
    'business' => array(
      'operations' => array(
        'index' => array(
          'help' => 'Retrieves businesses',
          'callback' => '_isaac_business_index',
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'access arguments append' => FALSE,
          'args' => array(
              'name' => 'fn',
              'type' => 'string',
              'description' => 'Function to perform',
              'source' => array('path' => '0'),
              'optional' => TRUE,
              'default' => '0',
              'name' => 'lat',
              'type' => 'int',
              'description' => 'Business Address Latitude',
              'source' => array('param' => 'lat'),
              'optional' => TRUE,
              'default' => '0',
              'name' => 'lon',
              'type' => 'int',
              'description' => 'Business Address Longitude',
              'source' => array('param' => 'lon'),
              'optional' => TRUE,
              'default' => '0',


  return $api;

function _isaac_business_index($fn, $lat, $lon) {
  $lat = doubleval($lat);
  $lon = doubleval($lon);
  return isaac_find_business_items($lat, $lon);

function isaac_find_business_items($lat, $lon) {
  // Compose query
  $query = db_select('node', 'n');
  $query->join('users', 'u', 'n.uid = u.uid');

  //$query->addExpression('field_address_thoroughfare'. 'field_address_postal_code','address');

//  $query->addExpression($lon,'my_lon');
 // $query->addExpression($lat,'my_lat');

  $query->condition('n.type', 'business', '=');
  $query->condition('n.status', NODE_PUBLISHED, '=');


  $items = $query->execute()->fetchAll();

  return $items;

There are some great tutorials on how to create custom REST endpoint:

We will review three PostGIS functions used in above code:

  • ST_Distance – Given two geometry points, this function returns distance between two points in spatial ref units
  • ST_MakePoint – Given latitude and longitude, this function returns a point geometry that can be used in ST_Distance and other PostGIS functions
  • ST_GeomFromWKB – Creates a geometry instance from a Well-Known Binary geometry representation (WKB)

So what’s happening here is that ST_Distance() will return distance values that we can use for filtering or sorting in our code. ST_Distance() takes two geometry points – user’s location and business location.

For user’s location, we pass in lat/long coordinates through URL and convert it to geometry point using ST_MakePoint() function.

For business location, we can do same with values from field_geodata_lat and field_geodata_lon columns or we can use field_geodata_geom value. Geofield module stores Well-Known Binary (WKB) data in that column and we use ST_GeomFromWKB() function to convert that into a geometry point.


We will test with following four businesses – also indicated in red marker on below map:

  1. Atlantic Coast Mortgage LLC – 4100 Monument Corner Dr, Fairfax, VA 22030
  2. Silver Spoon Caterers – 12450 Fair Lakes Cir, Fairfax, VA 22033
  3. Allegra Fairfax – 2812 Merrilee Dr, Fairfax, VA 22031
  4. Capitol Financial Partners – 1593 Spring Hill Road, Vienna, VA 22182

The user will be in Fairfax – indicated in blue marker on the map.

Build mobile apps with Drupal

We then call the endpoint we created above with latitude/longitude of user’s location (blue marker) as parameters:


We then get following results:

<result is_array="true">
  <title>Atlantic Coast Mortgages</title>
  <title>Silver Spoon Catering</title>
  <title>Allegra Fairfax</title>
  <title>Capitol Financial Partners</title>

As you can see from the distance values, the four businesses were retrieved based on lat/long location data sent in as parameters. They are sorted by distance from shortest to farthest.

As mentioned above, ST_Distance() function will return distance in spatial ref units. If you want it in meters, you can use ST_Distance_Sphere() in place of ST_Distance(). Make sure to check out the PostGIS documentation if you want to see what other functions are avaialble.


So in this post, I wanted to share my proof of concept that location feature can be made available in Drupal when it’s being used as a mobile backend – that is, without using Views.

We only passed in latitude and longitude to our custom REST endpoint but we can also add “limit” and “offset” param/value pairs to enable paging so that you get only 20-30 businesses at a time if there are a lot of businesses.

Published by Seong Bae

I am a web developer and digital marketing professional from Northern Virginia. I'm passionate about anything & everything about the web and the web technologies that empower us to do great things. bae.seong at gmail.com Linkedin Github