Getting the post terms ‘wp_get_post_terms’ per post when within the functions.php file

(Revised answer)

So I’m assuming that there are actually posts in the category (ID: 31), and based on the wp_get_post_terms() reference:

$post_id
(int) (Optional) The Post ID. Does not default to the ID of the global $post. Default 0.

It’s likely that you’re not passing the proper post ID to the wp_get_post_terms() function:

wp_get_post_terms( $post->ID, 'category', array(...) );

In that code, you have $post and yet, it’s not defined anywhere in your code as in the question.

So if you’re trying to get the ID of the current post in the WordPress Loop, where the post data is stored in the global $post variable, then you should first make the variable accessible in your function/code using global $post; like so:

global $post;
// here and after this line, you may now use $post->ID
if( $query->have_posts() ) :
...
endif;

Or you could also use get_the_ID() without having to do global $post;, particularly if all you wanted is to get the post ID:

wp_get_post_terms( get_the_ID(), 'category', array(...) ); // here I don't use $post->ID

And it’s probably worth mentioning that in standard templates such as page.php, the global $post variable is already “global-ed”, hence you may access the $post anywhere in the template. (Well, not exactly “anywhere”; however, I’m not going to dig deeper into that in this answer..)

Additional Notes

This is probably just a typo, but in the code in the question, you got a syntax error here:

foreach ( $brands as $brand ) {
  echo $brand->name;
}; // <- remove that ;

And you forgot the closing endif;..