get_the_category
works within the loop as well, don’t pass a post ID and it will default to the current post in the loop.
The first example in the docs for get_the_category
show how to output the url and name of the first (or only) category:
$categories = get_the_category();
if ( ! empty( $categories ) ) {
echo '<a href="' . esc_url( get_category_link( $categories[0]->term_id ) ) . '">' . esc_html( $categories[0]->name ) . '</a>';
}
EDIT: Your original code with the above example added:
<div class="container body-margin">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<div class="card">
<div class="row">
<?php $url = wp_get_attachment_url( get_post_thumbnail_id(get_the_ID()), 'thumbnail' ); ?>
<img src="https://wordpress.stackexchange.com/questions/327572/<?php echo $url ?>" class="img-responsive card-image" />
</div>
<div class="row card-body">
<?php
$categories = get_the_category();
if ( ! empty( $categories ) ) {
echo '<div><a class="card-body-category" href="' . esc_url( get_category_link( $categories[0]->term_id ) ) . '">' . esc_html( $categories[0]->name ) . '</a></div>';
}
?>
<div><h4 class="card-body-title"><b><?php the_title(); ?></b></h4></div>
<div><p class="card-body-date"><?php the_date(); ?></p></div>
</div>
</div>
<?php endwhile; ?>
</div>