t('Name of latitude field in Views query'),
'#type' => 'textfield',
'#default_value' => $views_plugin_style->options['ip_geoloc_views_plugin_latitude'],
'#description' => t('If you use a view based on the Location module, enter location_latitude. If the latitude is stored in a field, then enter the field\'s machine name. For instance, when using the Geofield, Geolocation field or Get Locations modules enter field_yourfieldname. Valid field names are on this page. For IP Geolocation Views and Maps visitor data, enter ip_geoloc_latitude. If your View involves other modules or relationships, prefix the name with the relevant table name(s), delimited by underscores.', array(
'!url' => url('admin/reports/fields')))
);
$form['ip_geoloc_views_plugin_longitude'] = array(
'#title' => t('Name of longitude field in Views query'),
'#type' => 'textfield',
'#default_value' => $views_plugin_style->options['ip_geoloc_views_plugin_longitude'],
'#description' => t('See comments above. When using the Geofield, Geolocation field or Get Locations modules you can leave this field empty.')
);
$differentiator = isset($form_state['differentiator'])
? $form_state['differentiator']
: $views_plugin_style->options['differentiator']['differentiator_field'];
if (isset($form_state['triggering_element'])) {
// Get here when any form element with #ajax was changed/clicked causing
// an auto-rebuild of the form. Can't put this in an ajax handler, as these
// are called AFTER the form rebuild, so too late.
if (strpos($form_state['triggering_element']['#id'], 'differentiator-differentiator-field') > 0) {
// Get here when is was the differentiator drop-down that was changed.
$differentiator = $form_state['triggering_element']['#value'];
unset($form_state['num_associations']);
}
}
$form_state['differentiator'] = $differentiator;
$form_state['no_cache'] = FALSE; // or AJAX won't work!
// Add wrapper for differentiator drop-down, association table and buttons.
// The id in the prefix must match the AJAX submit handlers below.
$form['differentiator'] = array(
'#type' => 'fieldset',
'#title' => t('Location differentiator and color associations'),
'#description' => t('You may designate one field from your view as a location differentiator. Locations that match the same corresponding differentiator value will have the same marker colors on the map. Examples of location differentiators are content type, taxonomy terms, gender. You may specify numeric and alphabetic ranges to match, too. So you can colour locations by age or height range, or by names or titles starting with some letter.'),
'#prefix' => '
',
'#suffix' => '
'
);
$fields = ip_geoloc_get_display_fields($views_plugin_style->display->handler);
$instances = ip_geoloc_get_field_instances($differentiator);
$instance = reset($instances);
if (empty($differentiator)) {
$description = t('Optionally select a location differentiator.');
}
else {
$description = t('Below associate %differentiator values with marker colors on the map.', array(
'%differentiator' => isset($instance) ? $instance['label'] : $fields[$differentiator]
)) . '
';
$field = field_info_field($differentiator);
if (!$field || $field['module'] == 'text') {
$description .= t('You may enter a range of values by separating "from" and "to" by a double hyphen.
Example: A--ZZ
You may omit "from" or "to" to created open-ended ranges.');
}
elseif ($field['module'] == 'number') {
$description .= t('You may enter a numeric range of by separating "from" and "to" by a double hyphen.
Example: 2.5--7.95
You may omit "from" or "to" to created open-ended ranges.');
}
}
$form['differentiator']['differentiator_field'] = array(
'#title' => t('Location differentiator'),
'#type' => 'select',
'#default_value' => $differentiator,
'#options' => $fields,
'#description' => $description,
'#ajax' => array(
'callback' => '_ip_geoloc_plugin_style_refresh_color_table_js',
'wrapper' => 'differentiator-wrapper'
)
);
if (!empty($differentiator)) {
// Container for the differentiator color associations table.
$form['differentiator']['color_table'] = array(
'#theme' => 'ip_geoloc_plugin_style_differentiator_color_table',
//'#prefix' => '',
//'#suffix' => '
'
);
_ip_geoloc_plugin_style_differentiator_color_table_form($form, $form_state);
$form['differentiator']['add-another'] = array(
'#type' => 'submit',
'#value' => empty($form_state['num_associations']) ? t('Add an association') : t('Add another association'),
'#weight' => 1,
'#submit' => array('_ip_geoloc_plugin_style_add_association_submit'),
'#ajax' => array(
'callback' => '_ip_geoloc_plugin_style_refresh_color_table_js',
'wrapper' => 'differentiator-wrapper',
'effect' => 'fade', // or 'none' or 'slide'
'speed' => 'fast', // or 'slow' or number of millisec
)
);
if (!empty($form_state['num_associations'])) {
$form['differentiator']['remove'] = array(
'#type' => 'submit',
'#value' => t('Remove bottom association'),
'#weight' => 2,
'#submit' => array('_ip_geoloc_plugin_style_remove_association_submit'),
'#ajax' => array(
'callback' => '_ip_geoloc_plugin_style_refresh_color_table_js',
'wrapper' => 'differentiator-wrapper',
'effect' => 'none', // or 'fade' or 'slide'
'speed' => 'fast', // or 'slow' or number of millisec
)
);
}
}
$is_openlayers = $form_state['renderer'] == 'openlayers';
$form['default_marker_color'] = array(
'#title' => t('Default location marker color'),
'#type' => 'select',
'#multiple' => FALSE, // !$is_openlayers,
'#size' => 1, // $is_openlayers ? 1 : 2, // may not be granted, 4 is minimum in some browsers
'#default_value' => $views_plugin_style->options['default_marker_color'],
'#options' => $is_openlayers ? ip_geoloc_openlayers_marker_layers() : ip_geoloc_marker_colors(),
'#description' => t('Select one color to apply to all location markers whose colors are not overridden by the Location differentiator above.'),
'#attributes' => array(
'class' => $is_openlayers ? array('marker-color ol') : array('marker-color gmap')),
'#attached' => array(
'css' => array(drupal_get_path('module', 'ip_geoloc') . '/css/ip_geoloc_admin.css')
)
);
$form['center_option'] = array(
'#title' => t('Map centering options'),
'#type' => 'radios',
'#default_value' => $views_plugin_style->options['center_option'],
'#options' => array(
IP_GEOLOC_MAP_CENTER_FIXED => t('Fixed center; see note below *)'),
IP_GEOLOC_MAP_CENTER_ON_FIRST_LOCATION => t('Use the first location returned by the view as the center of the map.'),
IP_GEOLOC_MAP_CENTER_ON_VISITOR => t("Center the map on the visitor's current location."),
IP_GEOLOC_MAP_CENTER_OF_LOCATIONS => t('Use the center of the rectangle whose sides are defined by the left-most, right-most, top and bottom locations (this option is insensitive to location clusters).'),
IP_GEOLOC_MAP_CENTER_OF_LOCATIONS_WEIGHTED => t('Use the center of gravity based on all locations (this option is sensitive to location clusters)')
),
'#description' => $is_openlayers
? t('*) If you want a fixed center, visit the "Center & Bounds" tab of the map edit page.', array(
'@url' => url('admin/structure/openlayers/maps/' . $views_plugin_style->options['map'] . '/edit')))
: t('*) If you choose the first option you may center the map via the special Map options "centerLat" and "centerLng" for example: %center_example', array(
'%center_example' => '{ "mapTypeId":"roadmap", "centerLat":-37.8, "centerLng":145 }'))
);
return $form;
}
/**
* Submit handler for the "Add another association" button.
*
* Increments the counter and forces a form rebuild.
*/
function _ip_geoloc_plugin_style_add_association_submit($form, &$form_state) {
$form_state['num_associations']++;
$form_state['rebuild'] = TRUE;
}
/**
* Submit handler for the "Remove" button.
*
* Decrements the counter and forces a form rebuild.
*/
function _ip_geoloc_plugin_style_remove_association_submit($form, &$form_state) {
$form_state['num_associations']--;
$form_state['rebuild'] = TRUE;
}
/**
* Ajax callback in response to new association rows being added or removed or
* the differentiator drop-down being changed.
*
* At this point the $form has already been rebuilt. All we have to do here is
* tell AJAX what part of the browser form needs to be updated.
*/
function _ip_geoloc_plugin_style_refresh_color_table_js($form, &$form_state) {
// Return the updated table, so that ajax.inc can issue commands to the
// browser to update only the targeted sections of the page.
return $form['options']['style_options']['differentiator'];
}
/**
* Submit handler as declared in ip_geoloc_form_alter().
*/
function ip_geoloc_plugin_style_differentiator_color_associations_submit($form, &$form_state) {
if (empty($form_state['view']) || empty($form_state['display_id']) || empty($form_state['differentiator'])) {
return;
}
$view_id = $form_state['view']->name;
$display_id = $form_state['display_id'];
$differentiator = $form_state['differentiator'];
$differentiator_color_associations = variable_get('ip_geoloc_' . $view_id . '_color_mappings', array());
if (!empty($form_state['values']['color_table'])) {
$i = 0;
foreach ($form_state['values']['color_table'] as $association) {
if (is_array($association[$differentiator])) { // e.g association['field_address']['und'][0]['postal_code']
foreach ($association[$differentiator][LANGUAGE_NONE] as $values) {
$differentiator_value = array();
if (is_array($values)) {
foreach ($values as $name => $value) {
if (!empty($value) && strpos($value, '|') === FALSE) {
$differentiator_value[$name] = $value;
}
}
}
else {
$differentiator_value[] = $values;
}
if (!empty($differentiator_value)) {
$differentiator_color_associations[$display_id][$differentiator][$i]['differentiator_value'] = $differentiator_value;
$differentiator_color_associations[$display_id][$differentiator][$i]['color'] = $association['color'];
$i++;
}
}
}
else { // plain text field
$differentiator_value = trim($association[$differentiator]);
if (!empty($differentiator_value)) {
$differentiator_color_associations[$display_id][$differentiator][$i]['differentiator_value'] = array($differentiator_value);
$differentiator_color_associations[$display_id][$differentiator][$i]['color'] = $association['color'];
$i++;
}
}
}
}
variable_set('ip_geoloc_' . $view_id . '_color_mappings', $differentiator_color_associations);
}
function _ip_geoloc_plugin_style_differentiator_color_table_form(&$form, &$form_state) {
$is_openlayers = $form_state['renderer'] == 'openlayers';
// First the saved rows...
// @todo: if $field['cardinality'] > 1, compress multiple differentiator values
// for the same color together in a single row
$view_id = $form_state['view']->name;
$display_id = $form_state['display_id'];
$differentiator = $form_state['differentiator'];
$differentiator_color_associations = variable_get('ip_geoloc_' . $view_id . '_color_mappings', array());
if (empty($differentiator_color_associations[$display_id][$differentiator])) {
$differentiator_color_associations[$display_id] = array($differentiator => array());
}
$row = 0;
foreach ($differentiator_color_associations[$display_id][$differentiator] as $association) {
if (!is_array($association)) { // data corrupt
break;
}
if (isset($form_state['num_associations']) && $row >= $form_state['num_associations']) {
break;
}
$form['differentiator']['color_table'][$row] = _ip_geoloc_plugin_style_diff_color_table_row_form($is_openlayers, $row, $differentiator, $association);
$row++;
}
// ... then the empty rows
if (!isset($form_state['num_associations'])) {
$form_state['num_associations'] = count($differentiator_color_associations[$display_id][$differentiator]);
}
while ($row < $form_state['num_associations']) {
$form['differentiator']['color_table'][$row] = _ip_geoloc_plugin_style_diff_color_table_row_form($is_openlayers, $row, $differentiator);
$row++;
}
}
function _ip_geoloc_plugin_style_diff_color_table_row_form($is_openlayers, $row, $differentiator, $association = NULL) {
$differentiator_value = empty($association) ? NULL : $association['differentiator_value'];
if (strpos($differentiator, 'field_') === 0) {
$field = field_info_field($differentiator);
$instances = ip_geoloc_get_field_instances($differentiator);
$instance = reset($instances);
$instance['label'] = ''; // no label, unless other modules override this
$instance['required'] = FALSE; // don't want asterisk to appear
// Make sure the text field is wide enough, especially for the case of a
// range, which needs to receive two values and a separator.
if (isset($instance['widget']['settings']['size']) && $instance['widget']['settings']['size'] < 15) {
$instance['widget']['settings']['size'] = 15;
}
$items[0] = empty($differentiator_value)
? array()
: is_array($differentiator_value) ? $differentiator_value : array($differentiator_value);
if (isset($instance['default_value'])) {
$items[0] += is_array($instance['default_value']) ? reset($instance['default_value']) : $instance['default_value'];
}
$form['#parents'] = array();
$form_state = array();
$form = field_default_form($instance['entity_type'], NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state);
if ($field['module'] == 'number' || $field['module'] == 'text') {
$form[$differentiator][LANGUAGE_NONE][0][key($field['columns'])]['#element_validate'] = array('ip_geoloc_range_widget_validate');
}
$form[$differentiator]['#attributes']['class'][] = $is_openlayers ? 'differentiator ol' : 'differentiator gmap';
}
else {
$form[$differentiator] = array(
'#type' => 'textfield',
'#default_value' => $differentiator_value,
'#element_validate' => array('ip_geoloc_range_widget_validate'),
'#attributes' => array(
'class' => $is_openlayers ? array('differentiator ol') : array('differentiator gmap')
)
);
}
$form['color'] = array(
'#type' => 'select',
'#multiple' => FALSE, // !$is_openlayers,
'#size' => 1, // $is_openlayers ? 1 : 2, // may not be granted, 4 is minimum in some browsers
'#default_value' => empty($association) ? NULL : $association['color'],
'#options' => $is_openlayers ? ip_geoloc_openlayers_marker_layers() : ip_geoloc_marker_colors(),
'#description' => NULL, // $is_openlayers ? NULL : t('Select one'),
'#attributes' => array(
'class' => $is_openlayers ? array('marker-color ol') : array('marker-color gmap')
)
);
// We'll manually set the #parents property of these fields so that their
// values appear in the $form_state['values']['color_table'] array.
$form[$differentiator]['#parents'] = array('color_table', $row, $differentiator);
$form['color']['#parents'] = array('color_table', $row, 'color');
return $form;
}
/**
* Return HTML for differentiator to color associations table.
*
* @param $variables
* An associative array containing $variables['form']: a render element
* representing the form.
*
* @ingroup themeable
*/
function theme_ip_geoloc_plugin_style_differentiator_color_table($variables) {
// Use the first form child to find out the name of the differentiator.
$form = $variables['form'];
$form_children = element_children($form);
if (empty($form_children)) {
return '';
}
$key = reset($form_children);
foreach ($form[$key] as $attribute_name => $element) {
if (drupal_substr($attribute_name, 0, 1) != '#' && $attribute_name != 'color') {
$differentiator = $attribute_name;
break;
}
}
if (empty($differentiator)) {
return '';
}
$instances = ip_geoloc_get_field_instances($differentiator);
$instance = reset($instances);
$differentiator_label = isset($instance) ? $instance['label'] : $differentiator;
$headers = array(
t('%differentiator value', array('%differentiator' => $differentiator_label)),
t('Associated marker color')
);
$rows = array();
foreach ($form_children as $key) {
$row = array('data' => array(), 'class' => array());
$row['data'][] = drupal_render($form[$key][$differentiator]);
$row['data'][] = drupal_render($form[$key]['color']);
$rows[] = $row;
}
$output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => 'differentiator-color-table')));
$output .= drupal_render_children($form);
return $output;
}
/**
* Extract an array of locations from the supplied views_plugin_style.
*
* @param type $views_plugin_style
* @return array of location objects, each containing lat/long and balloon_text
*/
function ip_geoloc_plugin_style_extract_locations($views_plugin_style) {
$latitude = trim($views_plugin_style->options['ip_geoloc_views_plugin_latitude' ]);
$longitude = trim($views_plugin_style->options['ip_geoloc_views_plugin_longitude']);
$view_id = $views_plugin_style->view->name;
$display_id = $views_plugin_style->display->id;
$differentiator = FALSE;
if (!empty($views_plugin_style->options['differentiator']['differentiator_field'])) {
$differentiator = $views_plugin_style->options['differentiator']['differentiator_field'];
$differentiator_color_associations = variable_get('ip_geoloc_' . $view_id . '_color_mappings', array());
if (empty($differentiator_color_associations[$display_id])) {
$differentiator_color_associations[$display_id] = array($differentiator => array());
}
}
$locations = array();
foreach ($views_plugin_style->view->result as $i => $row) {
$location = _ip_geoloc_plugin_style_extract_lat_lng($row, $latitude, $longitude);
if ($location) {
// Remaining row values go into the balloon
if (!empty($views_plugin_style->rendered_fields[$i])) {
$location->balloon_text = implode('
', $views_plugin_style->rendered_fields[$i]);
}
if ($differentiator) {
_ip_geoloc_plugin_style_set_marker_color($location, $row, $differentiator, $differentiator_color_associations[$display_id][$differentiator]);
}
$locations[] = $location;
}
}
// Allow other modules to implement hook_ip_geoloc_marker_locations_alter(&$locations, &$view)
drupal_alter('ip_geoloc_marker_locations', $locations, $views_plugin_style->view);
return $locations;
}
function _ip_geoloc_plugin_style_extract_lat_lng($row, $latitude, $longitude) {
$location = new stdClass();
// First look for $latitude and $longitude as node FIELD values:
$field_name = 'field_' . $latitude;
$delta = &drupal_static(__FUNCTION__);
if (isset($delta)) {
$delta++;
}
// Hack for http://drupal.org/node/1824538
// In the View, AddressField must have "Display all values in the same row"
// UNTICKED, while Geofield (and all other fields) must have it TICKED.
foreach ((array)$row as $key => $value) {
if (drupal_substr($key, -6) == '_delta' && strpos($key, 'field_data_field_') === 0) {
$delta = $value;
break;
}
}
if (!isset($delta) || !isset($row->{$field_name}) || $delta >= count($row->{$field_name})) {
$delta = 0;
}
if (!empty($row->{$field_name}[$delta]['raw'])) {
// For Geofield, Geolocation Field or Get Location modules lat/long are as follows:
// Geofield : field_[0]['raw']['geom'], eg POINT (144.976 -37.813) or MULTIPOINT ( (),(),() )
// Geolocation : field_[0]['raw']['lat'] and field_[0]['raw']['lng']
// Get Locations: field_[0]['raw']['latitude'] and field_[0]['raw']['longitude']
$base = $row->{$field_name}[$delta]['raw'];
if (isset($base['geo_type'])) { // Geofield
$is_point = ($base['geo_type'] == 'point');
if ($is_point) { // wkt more accurate than lat,lon in Geofield 7.x-1.x
$point = empty($base['geom']) ? $base['wkt'] : $base['geom'];
$is_point = (drupal_substr(trim($point), 0, 7) == 'POINT (');
if ($is_point) {
$parts = explode(' ', drupal_substr($point, 7));
$is_point = count($parts) > 1;
}
}
// $is_point==FALSE may indicate a MULTIPOINT cluster, which has its
// averaged center on 'lat' and 'lon' indices.
$location->longitude = $is_point ? $parts[0] : $base['lon'];
$location->latitude = $is_point ? (float)$parts[1] : $base['lat'];
}
elseif (isset($base['lng'])) { // GeoLocation
$location->latitude = $base['lat'];
$location->longitude = $base['lng'];
}
elseif (isset($base['longitude'])) { // Get Locations
$location->latitude = $base['latitude'];
$location->longitude = $base['longitude'];
}
else { // Other module
// Field values tend to be inside ...[0]['raw']['value']:
$location->latitude = $row->{'field_' . $latitude }[$delta]['raw']['value'];
$location->longitude = $row->{'field_' . $longitude}[$delta]['raw']['value'];
}
}
elseif (!empty($row->{$latitude}) && !empty($row->{$longitude})) {
// If not node fields then db table fields...
$location->latitude = $row->{$latitude};
$location->longitude = $row->{$longitude};
}
return isset($location->latitude) ? $location : NULL;
}
function _ip_geoloc_plugin_style_set_marker_color(&$location, $row, $differentiator, $differentiator_color_associations) {
if (!empty($differentiator)) {
if (!empty($row->{$differentiator})) {
$differentiator_value = $row->{$differentiator};
}
elseif (!empty($row->{'field_' . $differentiator})) {
$differentiator_values = $row->{'field_' . $differentiator};
if (is_array($differentiator_values)) {
$num_values = count($differentiator_values); // > 1 for taxonomy term with lineage
if (isset($differentiator_values[0]['raw'])) {
$differentiator_value = $differentiator_values[$num_values - 1]['raw'];
}
elseif (isset($differentiator_values[0]['rendered']['#markup'])) {
$differentiator_value = $differentiator_values[$num_values - 1]['rendered']['#markup'];
}
}
}
else {
$differentiator_value = '';
if (!isset($row->{'field_' . $differentiator})) {
drupal_set_message(t('IP Geolocation Views and Maps: no differentiator values found for %diff. Cannot set marker colors.', array(
'%diff' => $differentiator)), 'warning', FALSE);
}
}
if (!empty($differentiator_value)) {
foreach ($differentiator_color_associations as $association) {
$match = TRUE;
if (is_array($differentiator_value)) {
// Eg AddressField, has multiple subvalues. All must match the
// corresponding differentiator subvalues.
foreach ($association['differentiator_value'] as $name => $subvalue) {
if (isset($differentiator_value[$name]) && !ip_geoloc_is_in_range($differentiator_value[$name], $subvalue)) {
$match = FALSE;
break;
}
}
}
else { // simple values
$range = $association['differentiator_value'];
$match = ip_geoloc_is_in_range($differentiator_value, $range);
}
if ($match) {
$location->marker_color = $association['color'];
}
}
}
}
if (isset($location->marker_color) && is_array($location->marker_color)) {
$location->marker_color = reset($location->marker_color);
}
}
/**
* Perform token replacement, convert timestamps to date strings etc. for
*
* Store the rendered rows on the object passed in, which will typically be an
* instance of class views_plugin_style or subclass.
* Note that fields that have their Exclude box ticked, won't be rendered,
* Typical candidates for exclusion are the latitude and longitude fields.
*
* @param $views_plugin_style
* @param $result
* The result array on the view, e.g.
*/
function ip_geoloc_plugin_style_render_fields($views_plugin_style) {
if (!$views_plugin_style->uses_fields()) {
return;
}
if (!isset($views_plugin_style->rendered_fields)) {
$views_plugin_style->rendered_fields = array();
$field_ids = array_keys($views_plugin_style->view->field);
foreach ($views_plugin_style->view->result as $i => $row) {
$views_plugin_style->view->row_index = $i; // God knows why we need this...
foreach ($field_ids as $field_id) {
if ($views_plugin_style->view->field[$field_id]->options['exclude']) {
continue;
}
// Add the field label if it's provided
$label = $views_plugin_style->view->field[$field_id]->label();
$element = '';
$close_element = '';
if ($label) {
$label_type = $views_plugin_style->view->field[$field_id]->options['element_label_type'];
if ($label_type) {
$label_type = check_plain($label_type);
$element = '<' . $label_type;
$label_class = $views_plugin_style->view->field[$field_id]->options['element_label_class'];
if ($label_class) {
$element .= ' class="' . check_plain($label_class) . '"';
}
$element .= '>';
$close_element = '' . $label_type . '>';
}
if ($views_plugin_style->view->field[$field_id]->options['element_label_colon']) {
$label .= ': ';
}
$field_value = $views_plugin_style->view->field[$field_id]->theme($row);
// Add to the raw results set, so that the differentiator can pick it up
if (strpos($field_id, 'expression') === 0) {
$field_expr = 'views_' . $field_id; // eg 'views_expression_1'
if (empty($views_plugin_style->view->result[$i]->{$field_expr})) {
$views_plugin_style->view->result[$i]->{$field_expr} = array();
}
$views_plugin_style->view->result[$i]->{$field_expr}[] = $field_value;
}
$views_plugin_style->rendered_fields[$i][$field_id] = $element . $label . $close_element . ' ' . $field_value;
} // otherwise render with no label
else {
$views_plugin_style->rendered_fields[$i][$field_id] = $views_plugin_style->view->field[$field_id]->theme($row);
}
}
//$views_plugin_style->row_tokens[$i] = $views_plugin_style->view->field[$field_id]->get_render_tokens(array());
}
unset($views_plugin_style->view->row_index);
}
return $views_plugin_style->rendered_fields;
}
function ip_geoloc_get_display_fields($view_display) {
$fields = array('' => '<' . t('none') . '>');
foreach ($view_display->get_handlers('field') as $field_id => $field_handler) {
if (drupal_substr($field_id, 0, 6) != 'field_') {
// Example: 'title' becomes 'node_title'
$field_id = $field_handler->table . "_$field_id";
}
$fields[$field_id] = $field_handler->ui_name();
}
return $fields;
}
function ip_geoloc_get_field_instances($field_name) {
$instances = array();
foreach (field_info_instances() as $type_bundles) {
foreach ($type_bundles as $bundle_instances) {
foreach ($bundle_instances as $fld_name => $instance) {
if ($fld_name == $field_name) {
$instances[] = $instance;
}
}
}
}
return $instances;
}