WordPress User Taxonomy Saved Values

There are two errors in your code.

First one is the inconsistency in field names. Here’s your checkbox field:

 <input type="checkbox" name="competence-<?php echo esc_attr( $term->slug ); ?>" id="competence-<?php echo esc_attr( $term->slug ); ?>" value="<?php echo esc_attr( $term->slug ); ?>" <?php checked( true, is_object_in_term( $user->ID, 'competence', $term ) ); ?> />

And here’s the part you’re checking it:

foreach ( $terms as $term ) {
$term = esc_attr( $_POST[$term->slug] );

So your field has name competence-<TERM_SLUG>, but you’re checking it using only <TERM_SLUG>.

It should be:

foreach ( $terms as $term ) {
    $term = esc_attr( $_POST[ 'competence-' . $term->slug] );

Second problem is the way you’re setting the terms for object:

wp_set_object_terms( $user_id, array( $term ), 'competence', false);

Take a look at  wp_set_object_terms docs. This is the default call for this function:

 wp_set_object_terms( $object_id, $terms, $taxonomy, $append );

As you can see, the last param is $append and it tell if the term should be appended to the existing ones or should it overwrite existing ones. You pass false as the value for that param, so your foreach loop will overwrite existing terms – so only the last one will be saved.

One way to fix it would be like this:

$terms = array();
foreach ( $terms as $term ) {
    $term = esc_attr( $_POST[ 'competence-' . $term->slug] );
    $terms[] = $term;
}
wp_set_object_terms( $user_id, $terms, 'competence', false);