<div class="pr_grid_cell clearfix">
<?php
//for each category, show posts
$categories=get_categories();
foreach($categories as $cat) {
$args=array(
'post_type' => 'products',
'showposts' => -1,
'category__in' => array($cat->term_id)
);
$posts = new wp_query($args); // This is the best way to
if ($posts->have_posts()) while ($posts->have_posts()) { //condional if/while 2-in-1. If you dont check have_posts, you'll get an ugly error when nothings found.
the_post();//increments wps internal counter, Needed so that your loop doesnt run forever.
?>
<div class="pr_grid buy-online">
<span class="hcenter">
<h5><?= $cat->name ?></h5>
<? foreach($posts as $post) {
setup_postdata($post); ?>
<? if( get_field('buy_online_href') ): ?>
<?php // create our link now that the post is setup ?>
<span class="pr_img_href" href="https://wordpress.stackexchange.com/questions/174106/<? the_permalink(); ?>">
<img class="ii" src="<?php the_field('product_thumbnail'); ?>">
<a class="button" target="_blank" href="<?php the_field('buy_online_href'); ?>">Buy Online</a>
<a class="button" target="_blank" href="http://wordpress.stackexchange.com/store-locator">Find Near you</a>
</span>
<? endif ?>
<?php
} // foreach($posts
} // if ($posts
} // foreach($categories
?>
</span>
</div>
</div>
As mentioned, avoid using query_posts. In pretty much every case, it’s cleaner to just instantiate your own instance of the wp_query. I think the one thing missing, which is why it was running infinitely, was the lack of the_post(). That incremements the “counter” that tells the loop when it’s done. Without it, it will just run indefinitely.