I solved this by passing the array of terms into a sorting function. The array is passed by reference so nothing needs to be returned:
function sort_object_terms(&$terms) {
global $wpdb;
// First get an array of just the term IDs
$term_ids = array_map(function($term) {
return (int)$term->term_id;
}, $terms);
// Now get the order value for all the term IDs
$results = $wpdb->get_results(
"
SELECT woocommerce_term_id AS term_id, meta_value AS sort_order
FROM {$wpdb->woocommerce_termmeta}
WHERE meta_key = 'order' AND woocommerce_term_id IN ('" . implode("','", $term_ids) . "')
"
);
$term_orders = array();
foreach($results as $result) {
$term_orders[ $result->term_id ] = $result->sort_order;
}
// Finally, sort the terms by their term order value
uasort($terms, function($a, $b) use ($term_orders) {
if($term_orders[ $a->term_id ] === $term_orders[ $b->term_id ]) {
return 0;
}
return ( $term_orders[ $a->term_id ] > $term_orders[ $b->term_id ] ) ? 1 : -1;
});
}