Hello,

I'm using the geofield proximity exposed filter in a view and I'm having a lot of pain trying to theme it as I want.

There is a theme function theme_geofield_proximity but it doesn't allow to theme something as the #children is already build.

In my case, I need to only let the source field. The distance and unit are predefined, but the individual fields are set in geofield_proximity_element_process which, as far as I know, cannot be overriden except by hacking the core.

I suggest to put all the code into a themable function to let developpers to have real control over the fields.

Regards,

Alex

Comments

phayes’s picture

Alex, would you be willing to make a patch for this?

jerry’s picture

Would love to see this also, including a way of limiting the available radius options.

drubb’s picture

Here's a simple way to remove unit and distance fields, using the default values given in the view:

Create a small module implementing hook_element_info_alter and supplying a additional custom form process function:

/**
 * Implements hook_element_info_alter()
 * Add additional (!) custom process function
 */
function mymodule_element_info_alter(&$type) {
  if (isset($type['geofield_proximity']['#process'])) {
    $type['geofield_proximity']['#process'][] = 'mymodule_proximity_element_process';
  }
}

/*
 * Alter geofield views exposed form, remove distance and unit
 */
function mymodule_proximity_element_process($element, &$form_state, $form) {
  $element['distance']['#access'] = FALSE;
  $element['unit']['#access'] = FALSE;
  return $element;
}

This way you could also alter form labels, descriptions or anything else contained in this form.

PMorris’s picture

Thanks for posting this. I have it working to remove the distance and unit but where do I supply a default value for the search now that they are no longer exposed? I don't see an option in the views filter. For instance, if I always want it to show all results or everything within 5 kilometres. Sorry I don't have a lot of development experience!

EDIT:

Nevermind sorry i found it in views under the "Page" tab and then "Content: Geofield (field_ol_locator_geofield) - proximity (exposed)" because I'm using open layers locator and not just geofield

cmonnow’s picture

Thanks drubb for posting a simple method for altering the default exposed filters in views. For those interested, all the fields are defined in geofield.elements.inc in the base geofield module directory.

As a basic example for those wanting to modify a specific form (rather than all forms) I'll post some code below. This is important where your website may have many different proximity-based views with different search criteria, some where metres are more relevant than kilometres and manual entry more desirable than a drop-down distance.

Here is an example where you have say a particular view within a mini-pane that only needs 1, 2, 5, 10, 20 and 50 km options.

function custommodule_element_info_alter(&$type) {
  if (isset($type['geofield_proximity']['#process'])) {
    $type['geofield_proximity']['#process'][] = 'custommodule_proximity_element_process';
  }
}

/*
* Alter geofield views exposed form, remove distance and unit
*/
function custommodule_proximity_element_process($element, &$form_state, $form) {
//For example, we have a view with machine_name 'shiny rocks' and the panel pane name is 'panel_pane_1'
//You can find the values with dpr($form_state['view']->name) and dpr($form_state['view']->current_display)
 
	if ($form_state['view']->name == 'shiny_rocks' && $form_state['view']->current_display == 'panel_pane_1'){

		$element['distance']['#type'] = 'select'; //replace textfield with select

//Provide options drop-down to users
	    $element['distance']['#options'] = array(
				  1 => t('1 km'),
				  5 => t('5 km'),
				  10 => t('10 km'),
				  20 => t('20 km'),
				  50 => t('50 km')				  
				);
     $element['distance']['#default_value'] = 10; //set default to 10 km

//Find geofield unit constants in geofield.elements.inc (we use km here)
		$element['unit']['#default_value'] = GEOFIELD_KILOMETERS;

//Hide unit dropdown from modification
		$element['unit']['#access'] = FALSE;

//BTW, we will not override validation in this example to prevent HTML hacking (which allows any number, say 999999999), making website scraping still very easy

		return $element;
	}
 return $element;
}
cmonnow’s picture

Title: Make geofield proximity widget themable more easily » Make geofield proximity widget themable more easily (or How to Override View Proximity Elements)
Issue summary: View changes
cmonnow’s picture

Title: Make geofield proximity widget themable more easily (or How to Override View Proximity Elements) » Make geofield proximity widget themable more easily (or How to Override View Proximity Elements in the meantime)
Donovan’s picture

Thank you very much cmonnow and drub -- this is the exact solution I have been looking for.

I have implemented the module and successfully disabled the distance and unit fields. Now I am trying (with little success) to reduce the width of the exposed "from" / Origin field.

Is it possible to adjust the width of the "From" / Origin field through the custom module? When using Dev Tools I can adjust the field width by manipulating the CSS Size element through the browser; however, I cannot find the correct CSS selector to affect this change through the stylesheet.

I would appreciate any suggestions on how to adjust the field width via either the custom module or stylesheet.

Thanks!

cmonnow’s picture

Hi Donovan,

Unfortunately my module was so hacked from the outset I've never really played with native fields in Geofield (they're all hidden for my purposes).

Depending on which theme you're using can I assume you've created a sub-theme in /sites/default/themes/your_subtheme with a reference to your CSS modifications file (e.g. mods.css in the css folder) referenced in your sub-theme's .info file (e.g. stylesheets[screen][] = css/mods.css). If so, this file should be one of the last CSS files to be loaded so if it's being overrode by more specific CSS it would appear within your browser inspector.

Were you wanting to change the "from" label and origin input or the parent divs they're in? And did you want to hack all occurrences on your website or just one view, for example? In the immediate parent div to an origin you would have the specific field name class derived from the field name you assigned (e.g. form-item-field-geofield-distance-origin-lat for a latitude from the origin) and you can simply assign the CSS to the children as .form-item-field-geofield-distance-origin-lat label or .form-item-field-geofield-distance-origin-lat input[type="text"]. To change the "from" span .geofield-proximity-field-wrapper .geofield-proximity-origin-from should work fine.

Donovan’s picture

Thanks cmonnow! This was very helpful. I am using CSS Injector to make the desired changes vs. creating a subtheme.

I am looking to accomplish the following two objectives:

1. Reduce the width of the Origin input field
2. Hide the "from" label (prefix to the Orgin field)

Based on your guidance I was successful in using the following CSS rule to set the desired width of the Orgin field:

#edit-field-geofield-distance-origin {
    width: 180px;
}

Thank you!

Now I'm trying to determine the element name/schema to use to accomplish objective 2 above (hide the "from" label). The precise element is the following from geofield.element.inc:

'#prefix' => '<span class="geofield-proximity-origin-from">' . t('from') . '</span>',

... taken from this excerpt:

//Create textfield for geocoded input
  $element['origin'] = array(
    '#type' => (!empty($element['#origin_element'])) ? $element['#origin_element'] : 'textfield',
    '#title' => t('Origin'),
    '#prefix' => '<span class="geofield-proximity-origin-from">' . t('from') . '</span>',
    '#title_display' => 'invisible',
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['origin']) ? $element['#default_value']['origin'] : FALSE,
  );

Is it possible to accomplish this via the custom module in a manner similar to:

$element['element-identifier-for-from-label']['#access'] = FALSE; ??

Thoughts?

cmonnow’s picture

Hi Donovan,

No problem.

And yep, to remove the "from" prefix you should have no problems in simply adding

unset($element['origin']['#prefix']);

to your equivalent "custommodule_proximity_element_process" function within your custom module.

Cheers

Donovan’s picture

Hi Cmonnow, Thank you very much. Worked perfectly! Your suggestions and helpfulness are greatly appreciated. If I ever make it to Australia I'll have to look you up and buy you a pint or two.

Kindest regards.

cojomojo’s picture

Hello,

First off, this is good stuff! Thank you cmonnow! I was trying to edit the way the geofield is displayed for hours and then i stumbled across this. It looks promising, and many people said it works for them, but I cant get it to work. Im sure its me but maybe you can help me. Here is my code:

function wff_geofield_proximity_search_form_alter(&$form, &$form_state, $form_id) {
   if (($form_id == 'views_exposed_form') &&  ($form['#id'] == 'views-exposed-form-store-locator-map-page-1')) {
        dpm($form_state['view']->name);
        dpm($form_state['view']->current_display);
  } 
};

function wffGeofieldProximitySearch_element_info_alter(&$type) {
  if (isset($type['geofield_proximity']['#process'])) {
    $type['geofield_proximity']['#process'][] = 'wffGeofieldProximitySearch_proximity_element_process';
  }
};

/*
* Alter geofield views exposed form, remove distance and unit
*/
function wffGeofieldProximitySearch_proximity_element_process($element, &$form_state, $form) {
    if ($form_state['view']->name == 'store_locator_map' && $form_state['view']->current_display == 'page_1'){
        $element['distance']['#type'] = 'select'; 

        $element['distance']['#options'] = array(
                  1 => t('1 Mile'),
                  5 => t('5 Miles'),
                  10 => t('10 Miles'),
                  20 => t('20 Miles'),
                  50 => t('50 Miles')
                );

     $element['distance']['#default_value'] = 10;

        $element['unit']['#default_value'] = GEOFIELD_MILES;
		//Hide unit dropdown
        $element['unit']['#access'] = FALSE;

        return $element;
    }
 return $element;
};

Nothing happens at all (besides the messages I printed using dpm to get the view name and display name).

cmonnow’s picture

Hi cojomojo,

Since your dpm works I assume your module name is "wff_geofield_proximity_search". Therefore your hook_element_info_alter() function is named incorrectly (you used camelCased WffGeofieldProximitySearch instead). Although not essential to work I also changed the custom #process function name for consistency (and easier debugging). I've also removed the semi-colons after the functions' final curly brackets (since they're unnecessary in PHP).

Cheers

function wff_geofield_proximity_search_form_alter(&$form, &$form_state, $form_id) {
   if (($form_id == 'views_exposed_form') &&  ($form['#id'] == 'views-exposed-form-store-locator-map-page-1')) {
        dpm($form_state['view']->name);
        dpm($form_state['view']->current_display);
  }
}

function wff_geofield_proximity_search_element_info_alter(&$type) {
  if (isset($type['geofield_proximity']['#process'])) {
    $type['geofield_proximity']['#process'][] = 'wff_geofield_proximity_search_proximity_element_process';
  }
}

/*
* Alter geofield views exposed form, remove distance and unit
*/
function wff_geofield_proximity_search_proximity_element_process($element, &$form_state, $form) {
    if ($form_state['view']->name == 'store_locator_map' && $form_state['view']->current_display == 'page_1'){
        $element['distance']['#type'] = 'select'; 
        $element['distance']['#options'] = array(
                  1 => t('1 Mile'),
                  5 => t('5 Miles'),
                  10 => t('10 Miles'),
                  20 => t('20 Miles'),
                  50 => t('50 Miles')
                );
     $element['distance']['#default_value'] = 10;
        $element['unit']['#default_value'] = GEOFIELD_MILES;
        //Hide unit dropdown
        $element['unit']['#access'] = FALSE;
        return $element;
    }
 return $element;
}
cojomojo’s picture

Thank you cmonnow, being new to drupal I didnt realize that the function naming like was required for modules, i thought it was just best practice. It works now perfect!

portabledesign’s picture

hi guys,
great work, i love drupal but have always avoided hooks and custom modules

I am looking to have 2 search dropdowns,

one a hardcoded / Taxomonmy term with location / node with location list of locations that the user can choose from (ie train station)

the second dropdown similar to what you have above, 1km, 2km, 3km, 4km, etc

this will show all the nodes in this raduis( which are apartments)

is there anyway do do this without creating a module, ie is there any setup in views to make this happen

if not can someone help me with a hook / module
i am using openlayers

thanks again

bcobin’s picture

Thanks SO much for this cmonnow - with the appropriate changes to customize for my view, this works a treat! Excellent work...

thatpatguy’s picture

** Edited **

I removed my original post due to finally discovering that there was another module being used overwriting mine. Thanks again or all the work done here, super helpful!

astringer’s picture

Thanks cmonnow and cojomojo. It works great and I now know how out make a custom module. :-)

malcomio’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.