Using auto-updating country/zone select boxes

Ãœbercart has been wired to automatically update a zone select box on a form when the corresponding country select box is changed. In order for this to work, you need to keep in mind two simple things:

  1. You should use a similar prefix in the keys of the form array for the country/zone select boxes. The JS that gets added uses this to detect which form element should be updated when a country select is changed. Example:
    ['ship_to']['delivery_zone'] = uc_zone_select(uc_get_field_name('zone'));
    $form['ship_to']['delivery_country'] = uc_country_select(uc_get_field_name('country'));

    Notice how the keys both start with delivery_ and end with zone and country respectively.

  2. You have to include a special check in your form function for the updated zones to be considered as valid options for the select box. The Drupal forms API will only accept a value for a select box that is included in the options array when the form is built. Because we're dynamically changing the options, to submit it right you need to account for the possibility that the options are different.
    The easiest way to do this is by checking $_POST for the value of your country select and having your call to uc_zone_select() take into account the fact that you might want to get a different country's zones besides the default. Using the form names from above, this looks like the following:
    if (isset($_POST['delivery_country'])) {
    $country_id = intval($_POST['delivery_country']);
      else {
    $country_id = NULL;
    $form['delivery_zone'] = uc_zone_select(uc_get_field_name('zone'), NULL, NULL, $country_id);
    $form['delivery_country'] = uc_country_select(uc_get_field_name('country'));

Note: As far as I can tell, you can't use this directly for CCK fields. Instead, what I had to do was create a proxy field via a hook_form_alter(), hide the CCK inputs, and then replace the CCK input values in a submit handler.
uc_country_select(), uc_zone_select(), uc_get_field_name()