I found a solution which requires a little code. The idea is that we make the term weights the same as the term names. Then we can use views to sort against the term weights.
Using hook_taxonomy_term_presave()
, we can update the term weight to match the term name for all terms saved from now into the future. It uses intval($term->name)
which nicely gets any numbers at the beginning of a term name (or 0 for alphabetical term names).
/**
* Implements hook_taxonomy_term_presave().
*/
function mymodule_taxonomy_term_presave($term) {
// For all terms, make the weight equal to the term name. We can then use weight for
// numerical sorting to fix the bug where numeric term names sort in character code order.
$vocab_name = 'vocab_machine_name';
$vocab = taxonomy_vocabulary_machine_name_load($vocab_name);
if ($term->vid == $vocab->vid) {
$term->weight = intval($term->name);
}
}
The above code will only work for terms that are saved from now into the future.
If you want to update all existing terms, try this function. It only took about 1 second to update 1,000 rows on my development machine:
/**
* Update existing taxonomy term weights.
*/
function resave_numeric_term_weights() {
// Get vid from machine_name
$vocab_name = 'vocab_machine_name';
$vocab = taxonomy_vocabulary_machine_name_load($vocab_name);
$result = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->condition('t.vid', $vocab->vid)
->execute();
$terms = $result->fetchAll();
foreach ($terms as $term) {
// Make the weight equal to the intval() of the term name.
db_update('taxonomy_term_data')
->fields(array('weight' => intval($term->name)))
->condition('tid', $term->tid)
->execute();
}
drupal_set_message(t('Updated term weights for @num terms', array('@num' => count($terms))));
}