Is there a way to change the order of exposed filter fields by hook_form_alter'ing their weights? I'm trying to add a few new form elements with hook_form_alter and can't get them to show up anywhere except the end of the for.

The other alternative I come up with is perhaps a plugin that just adds blank form elements to filters, is such a thing feasible?

Comments

dawehner’s picture

Status: Active » Fixed

it's fapi so it has to work :) You probably doing something wrong here.

manatwo’s picture

Status: Fixed » Active

I would think so too but I cannot seem to make it work. If I make a view with just NID and Node Title exposed filters, set NID to come before Title in the UI but make $form['title']['#weight'] higher than the nid weight in my alter, there is no change.

dawehner’s picture

The problem is that there is some theming on exposed form. You would have to override it, sadly.

esmerel’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

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

LGLC’s picture

Has anyone got an example of how to do such theming? I'm really struggling trying to get new form elements to the the top of exposed filter forms.

Thanks.

manatwo’s picture

Yes, all of it is handled in views-exposed-form.tpl.php, which you can override in your theme to print out your fields manually. IIRC, the extra fields are gonna be in the $button variable in that template, so you might want to do some preprocessing in template.php

LGLC’s picture

Thanks for your help, manatwo. I finally managed to do it after reading your post. Thank you.

kgthompson’s picture

I was able to alter the order without overriding the template. I am using Views 3, but I think this will work in Views 2 as well.

Alter the order of the filters in $form['#info'] in your form_alter and this should alter the order the widgets print out in the template without having to do any custom templating.

maciej.zgadzaj’s picture

A small update on this, if someone faces similar problem in the future, as I just did myself, trying to place my new exposed form item in-between "widgets" generated automatically by the view - the solution is to turn that new form item into a widget, and then re-order widget array in the $form['#info'].

In my case I was adding new community form item into Views exposed form, and then wanted it to be displayed as a second element in the form, right after filter-title generated by the view:

function mymodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'views_exposed_form' && $form['#id'] == 'views-exposed-form-mw-group-list-page-1') {
    // Add new form item.
    $form['community'] = array(
      '#type' => 'radios',
      '#title' => t('Community'),
      '#options' => $options_array,
      '#default_value' => $default_value,
    );
    // Create widget from new form item and place it as a second element.
    $new_form_info = array(
      'filter-title' => $form['#info']['filter-title'],
      'filter-community' => array('value' => 'community'),
    );
    $form['#info'] = array_merge($new_form_info, array_diff_assoc($form['#info'], $new_form_info));
  }
}

Obviously the code responsible for re-ordering $form['#info'] will look different depending on where the new form item should be displayed.

Mixologic’s picture

Title: Exposed Filter Field #weight » Exposed Filter Field #weight has no impact on ordering.
Version: 6.x-2.9 » 7.x-3.x-dev
Status: Closed (fixed) » Active

Im re-opening this as Im hoping somebody with deeper views experience can chime in on the best way to handle this.

I too needed to shim in a #markup bit in between various exposed filters, and I did exactly what maciej.zgadzaj did above. All the while I was wondering why a form alter, or even a form #afterbuild seems to require such jostling of form['#info'] just to reorder the widgets. Is there a better way to accomplish this?

dotist’s picture

the solution from maciej.zgadzaj in #10 worked great for me - thanks!

lpeabody’s picture

#10 worked for me as well. Totally weird...

blacklabel_tom’s picture

#10 worked for me too.

Any plans to get the form to respect #weight?

Cheers

Tom

michaellenahan’s picture

Thank you very much maciej.zgadzaj for #10!

Here is some code for putting an element into an exposed form at a certain position.

In this case, $insert_index = 2 means that the new element will go after the second element.

/**
 * Implements hook_form_FORM_ID_alter().
 */
function f_event_form_views_exposed_form_alter(&$form, $form_state, $form_id) {
  if ($form['#id'] == 'views-exposed-form-calendars-panel-pane-1') {

    // here's a form element that we can just add to the form.
    $form['tests_taken'] = array(
      '#type' => 'checkboxes',
      '#options' => drupal_map_assoc(array(t('SAT'))),
      '#title' => t('What standardized tests did you take?'),
      '#attributes' => array(
        'name' => 'example-checkboxes[]'
      ),
    );

    // this value determines the position of the new element.
    $insert_index = 2;
    
    $element_to_insert = array();
    $element_to_insert['filter-tests_taken'] = array(
      'value' => 'tests_taken',
    );
    //dpm($form['#info'], '$form[\'#info\']');
    //dpm($element_to_insert, '$element_to_insert');
    $form_info_top = array_slice($form['#info'], 0, $insert_index);
    //dpm($form_info_top, '$form_info_top');
    $form_info_bottom = array_slice($form['#info'], $insert_index);
    //dpm($form_info_bottom, '$form_info_bottom');
    $new_form_info = $form_info_top + $element_to_insert + $form_info_bottom;
    //dpm($new_form_info);
    $form['#info'] = $new_form_info;

    //dpm($form);
  }
}

leex’s picture

You can use normal weights if you're willing to ignore templating, which for me was totally acceptable. I set weights on exposed filters using form_alter:

$form['field_topics_event_tid']['#weight'] = '1';
$form['items_per_page']['#weight'] = '2';
$form['keys']['#weight'] = '3';
$form['submit']['#weight'] = '4';

Then to ignore templating, just put an empty theme hook in template.php:

/**
 * Required to disable normal themeing on exposed form filters, so weighting works correctly.
 */
function template_views_exposed_form($variables) {}

Yes this is not a very ideal way of doing it as it removes templating from all views exposed filter forms, but it was much quicker for me than doing the ordering properly.

profak’s picture

Issue summary: View changes

Maciej.zgadzaj's solution is great!

Thanks!
#weight still not supported. It looks fine because of way widgets render and work.

drupalshrek’s picture

Thank you very much michaellenahan for your code in #15 as this works great!

drupalshrek’s picture

Moving the code from michaellenahan into a function:

/**
 * Insert the given field into a particular position in the form.
 * 
 * @param $form
 *   The form which is going to have the field inserted. Passed by reference.
 * @param string $file_key
 *   The key in the form where the field is to be found. e.g. if $form['foo']
 *   contains the field, then use 'foo' as this parameter.
 * @param int $insert_index
 *   Index of where in the form the field should be placed.
 */
function views_tweaks_insert_field(&$form, $field_key, $insert_index) {
	// this value determines the position of the new element.
  $element_to_insert = array();
  $element_to_insert[$field_key] = array(
      'value' => $field_key,
  );

  $form_info_top = array_slice($form['#info'], 0, $insert_index);
  $form_info_bottom = array_slice($form['#info'], $insert_index);
  $new_form_info = $form_info_top + $element_to_insert + $form_info_bottom;
  $form['#info'] = $new_form_info;
}

Example of call to the function to add 2 fields.

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Adds the fields 'field_project_start_date' and 'zoom' to the end of the filter form.
 */
function views_tweaks_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
	if ($form['#id'] == 'views-exposed-form-activities-list-calendar') {

          // First add the 'field_project_start_date' field

	  // Creating the date/time element starts here
	  // Provide a default date in the format YYYY-MM-DD HH:MM:SS.
	  $date = date();  // e.g. '2008-12-31 00:00:00';
	  // Provide a format using regular PHP format parts (see documentation on php.net).
	  // If you're using a date_select, the format will control the order of the date parts in the selector,
	  // rearrange them any way you like. Parts left out of the format will not be displayed to the user.
	  $format = 'd-m-Y';
	  $form['field_project_start_date'] = array(
	     '#type' => 'date_popup', // types 'date_popup', 'date_text' and 'date_timezone' are also supported. See .inc file.
	     '#title' => t('Include Date'),
	     '#default_value' => $date,
	     '#date_format' => $format,
	     '#date_label_position' => 'within', // See other available attributes and what they do in date_api_elements.inc
	     '#date_timezone' => 'America/Chicago', // Optional, if your date has a timezone other than the site timezone.
	     '#date_increment' => 15, // Optional, used by the date_select and date_popup elements to increment minutes and seconds.
	     '#date_year_range' => '-4:+4', // Optional, used to set the year range (back 3 years and forward 3 years is the default).
	     '#datepicker_options' => array(), // Optional, as of 7.x-2.6+, used to pass in additional parameters from the jQuery Datepicker widget.
	  	 '#size' => 10,
	  );
	  
	  views_tweaks_insert_field($form, 'field_project_start_date', 7);
          		
          
          // Now add 'zoom' field
          $form['zoom'] = array(
	    '#multiple' => FALSE,
	    '#size' => 0,
	    '#weight' => 1000,
	    '#title' => 'Period',
	    '#type' => 'select',
	    '#options' => array(
	      '1y' => '1 Year',
	      '2y' => '2 Years',
	      '3y' => '3 Years',
	      '4y' => '4 Years',
              '5y' => '5 Years',
            ),
	  '#default_value' => '10y',
          );
	}
	
	views_tweaks_insert_field($form, 'zoom', 7);
}
DrCord’s picture

Thank you drupalshrek, maciej.zgadzaj and michaellenahan!!

jedihe’s picture

#15 worked great for me! thanks!

bas.bakker’s picture

#15 worked like a charme

sebi’s picture

If you dont care about theming, you can simply set the parent element ['#theme'] to an empty string to reset formatting and handle weights.

In my case...

<?php
  // ... some random stuff to programmatically get exposed form
  $form = drupal_build_form('views_exposed_form', $form_state);
  $form['#theme'] = '';
  // ...
  $form['some_field']['#weight'] = 1;
?>
codethenode’s picture

#15 FTW. Thanks michaellenahan!

ropic’s picture

#23 works too, great !

konst_8’s picture

You can use drupal element_sort function, applied to $form['#info'] array:

function YOUR_MODULE_form_views_exposed_form_alter(&$form, &$form_state, $form_id){
  if ($form['#id'] == 'YOUR-FORM-ID') {

    // change order of views exposed filters

    $form['#info']['filter-status']['#weight'] = -50;
    $form['#info']['filter-rid']['#weight'] = -45;
    $form['#info']['filter-title']['#weight'] = -40;
    $form['#info']['filter-mail']['#weight'] = -35;
    $form['#info']['filter-name']['#weight'] = -30;
    
    uasort($form['#info'], 'element_sort');
  }
}
Jigar.addweb’s picture

Issue tags: +exposed filters, +weight
Lissy’s picture

konst_8, You made my day. ;-)
#26 works perfekt for me.

Meera.b’s picture

#10 worked perfectly.

Collins405’s picture

Tried everything, 26 was the only one that worked for me. Thanks!