6

I have created a FAPI form with an element of #type => date and it works as expected.

$form['date'] = array(
  '#type' => 'date',
  '#title' => t('Event date:'),
);

However, the options displayed in the year field range from 1900 - 2050. I would like to be able to limit this to a much smaller range starting with the current year. What would be the best way to accomplish this?

  • I don't know the answer, but if you look at form_process_date you can see the defaults being added. Probably you'll want to be messing with the $options parameter somehow. – Letharion May 15 '12 at 18:44
7

If you don't want to change every date field—which might have side effects else where on the site—you can easily do it on specific form elements.

function example_form(&$form, &$form_state)  {
  $form['birthday'] = array(
    '#type' => 'date',
    '#title' => t('Birthday'),
    '#required' => TRUE,
    // Add a second process function so we can change the years:
    '#process' => array('form_process_date', 'example_fix_year_range'),
  );

  return $form;
}

/**
 * Follow form_process_date() and re-do the years.
 */
function example_fix_year_range($element) {
  $year = format_date(REQUEST_TIME, 'custom', 'Y');
  $element['year']['#options'] = drupal_map_assoc(range($year - 120, $year));
  return $element;
}
1

You can implement hook_element_info_alter() to alter the definition of the form element given from system_element_info().

The default definition is the following one:

  $types['date'] = array(
    '#input' => TRUE, 
    '#element_validate' => array('date_validate'), 
    '#process' => array('form_process_date'), 
    '#theme' => 'date', 
    '#theme_wrappers' => array('form_element'),
  );

form_process_date() is the function that set the year sub-element. If you replace it with your own process function, or add it, you can alter that limit.
The code used from the default preprocess function is the following one.

  // Output multi-selector for date.
  foreach ($order as $type) {
    switch ($type) {
      case 'day':
        $options = drupal_map_assoc(range(1, 31));
        $title = t('Day');
        break;

      case 'month':
        $options = drupal_map_assoc(range(1, 12), 'map_month');
        $title = t('Month');
        break;

      case 'year':
        $options = drupal_map_assoc(range(1900, 2050));
        $title = t('Year');
        break;
    }

    $element[$type] = array(
      '#type' => 'select', 
      '#title' => $title, 
      '#title_display' => 'invisible', 
      '#value' => $element['#value'][$type], 
      '#attributes' => $element['#attributes'], 
      '#options' => $options,
    );
  }

As alternative, you can implement hook_preprocess_date(), which is executed when theme_date() is called. (In Drupal 7, every theme function executes preprocess hooks, not just a theme function using a template file.) Doing so, you can alter the form element the preprocess function gets in $variables['element'].

I would rather use the latter method, even though both the methods would work; it is simpler, as it doesn't require two hooks.

  • I implemented the latter solution as you suggested and it worked like a charm. Thanks! – markdorison May 15 '12 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.