*(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](https://developer.wordpress.org/reference/functions/wp_get_post_terms/): > **`$post_id`**<br> (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()`](https://developer.wordpress.org/reference/functions/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;`..