Fun with Views and Location

For my day job, I've been using the Location module quite extensively. Thanks to its many contributed modules, it integrates with various parts of the Drupal ecosystem, including Views, making it a good base to start developing your own location-aware features. Here are some puzzles I faced during the past few days:

Filtering views with existing cities

The city filter is a text field. That's not ideal because it does not give users a hint about existing cities in the database. Here's a simple city filter that displays a drop-down list only containing existing cities:

<?php
// @file mymodule_handler_filter_location_city.inc

class mymodule_handler_filter_location_city extends views_handler_filter {
  function
value_form(&$form, &$form_state) {
   
$options = db_query_array('SELECT DISTINCT(l.city) FROM {location} ORDER BY l.city ASC', QUERY_ARRAY_MODE_SINGLETON_KEY_VALUE);
   
$form['value'] = array(
     
'#type' => 'select',
     
'#title' => t('City'),
     
'#default_value' => isset($this->value) ? $this->value : NULL,
     
'#options' => $options,
     
'#multiple' => TRUE,
    );
    return
$form;
  }

  function
admin_summary() {
    if (!empty(
$this->options['exposed'])) {
      return
t('exposed');
    }
  }
}

// @file mymodule.views.inc

/**
* Implementation of hook_views_data().
*/
function mymodule_views_data() {
 
$data['location']['city2'] = array(
   
'title' => t('City (dropdown)'),
   
'help' => t('The city of the selected location.'),
   
'filter' => array(
     
'field' => 'city',
     
'handler' => 'mymodule_handler_filter_location_city',
    ),
  );
  return
$data;
}

/**
* Implementation of hook_views_handlers().
*/
function mymodule_views_handlers() {
  return array(
   
'info' => array(
     
'path' => drupal_get_path('module', 'mymodule'),
    ),
   
'handlers' => array(
     
'mymodule_handler_filter_location_city' => array(
       
'parent' => 'views_handler_filter',
      ),
    ),
  );
}
?>

Note that you'll need the db_query_array function I defined earlier.

Node views with author's location fields

This was a nice puzzle: given a view of nodes, how do you display the location fields of each node's author? Note that I don't want the node's location fields. Here's my solution: The idea is to create an explicit relationship between node and user, such that the location data can be pulled out of the user, instead of the node.

  • Create a new relationship between node and user:
<?php
// @file mymodule.views.inc

/**
* Implementation of hook_views_data_alter().
*/
function mymodule_views_data_alter(&$data) {
 
$data['node']['uid'] = array(
   
'title' => t('User'),
   
'help' => t('Relate a node to the user who created it.'),
   
'relationship' => array(
     
'base' => 'users',
     
'field' => 'uid',
     
'handler' => 'views_handler_relationship',
     
'label' => t('user'),
    ),
  );
}
?>
  • In the node view, instantiate the node/user relationship.
  • Add location fields based on the given relationship.

Location searching via Content Profile views

This one eluded me for 2 days until I hit upon this simple solution. Given a view of Content Profile nodes, how do you provide a Search Terms filter that includes user locations? I won't bore you with my many unfruitful attempts, so here's the solution: Since the Search Terms filter searches the 'node' index, I need the user location information to be indexed there. Therefore, I update the Content Profile node index with the author's location, during hook_nodeapi('update index'):

<?php
// @file mymodule.module

/**
* Implementation of hook_nodeapi().
*/
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  global
$user;

  if (
$op == 'update index') {
   
$output = array();
    if (
$node->uid) {
      if (
$node->type == 'experience') { // that's my content profile node type
        // Add the user location.
       
$locations = location_load_locations($node->uid, 'uid');
        if (!empty(
$locations)) foreach ($locations as $location) {
         
$output[] = theme('location', $location);
        }
      }
    }
    return
implode('<p>', $output);
  }
}
?>

You'll need to rebuild your index for this to work.

There! Now wasn't that fun!

Comments

Exposed filter to display desired fields

there are three exposed filters in my view. one is to enter term ids (not term name)seperated by ',' . I did it by arguments and altering exposed filter form, created a textfield and altered the #action. Second one is simple node type. Third one is for the fields to display i.e there are checkboxes for title, teaser, body. Now i have to show only those fields. How can i do that??

I don't know if there's

I don't know if there's module to select fields to be displayed in an exposed filter.

What about filtering with

What about filtering with multiple tids (not term names) with comma seperated??

Streets from a custom list

Could use this code to provide a drop down for predefined street addresses?

Node views with author's location fields - setup

This is exactly what I'm looking for, but implement how exactly?

I've created a "user_location.inc" file with the above code. And a "user_location.info" file.

Created a folder - "user_location_mod", inserted files, and put it into the modules folder.

What about a ".MODULE" file? Without it, there is no module to enable...

And then there will be a new type relationship I can add? Thus the CITY (or any fieled I guess) field will then have a drop-down that includes this relationship?

Thanks. Mercury FLiXER

where do you put this intersting code?

Hi,

Thanks for the insight. i apologise in advance if my questions sounds a little damb. but where exactly do you in put the code you have specied? i won't mention that i a newbee..but you get the idea.

thanx.

Tu run this code: * Create a

Tu run this code:

  • Create a new, empty module with some name.
  • In each snippet of code above, you will find an @file comment. That gives you a hint about the filename: just replace "mymodule" with your module's name.
  • In each snippet, replace all occurrences of "mymodule" with your module name.
  • Enjoy!

you put them in a new module

you put them in a new module dude if u see the code it has stuff like this: function (my_module) replace the mymodule with your module name activate the module and ready you go

Hello, I enabled the module

Hello,

I enabled the module containng the above code in the appropriate files. How do i enable it in a view?

Clear the cache then find the

Clear the cache then find the filter called "City (dropdown)" in the "Location" group.