Let’s say we want to have our posts displayed like the following.

Category 1

  • Post 1
  • Post 2
  • Post 3

Category 2

  • Post 1
  • Post 2
  • Post 3

You will quickly realise that using the standard WordPress loop you won’t quite get what you want.

The problem

Using the conventional loop, you will only have access to the categories (terms) of that single post at that point resulting in the following

Category 1
Post 1
Category 1
Post 2
Category 1
Post 3

The Solution

The solution is actually quite simple. Get the list of terms first and loop over each term, in this loop get the posts tagged with that term. I am going to use get_terms which is a helper that ultimately calls WP_Term_Queryto get the list of terms first.

<?php
$terms = get_terms( array(
  "taxonomy" => "category",
) );

The above returns an array of term objects with properties such as term_id. Now that we have the terms, we are going to loop through them, passing the term_id to the get_posts()function to get the list of posts tagged with that term. get_posts() ultimately calls WP_Query and you could use that class if your case requires it. In my case, I just want the title of the post.
Our code now becomes the following:

<?php
$terms = get_terms( array(
  "taxonomy" => "category",
) );

foreach ($terms as $term) : 
  $posts = get_posts(["post_type" => "store", "cat" => $term->term_id]);
?>
  <h4><?= $term->name; ?></h4>
  <ul>
  <?php foreach($posts as $post) : ?>
    <li><?= $post->post_title; ?></li>
  <?php endforeach; ?>
  </ul>
<?php endforeach; ?>