Adding a second loop breaks everything

The root problem here is a missing endif; on the second loop.

But, there are a few changes we can make to improve this and make things work, this loop, will work a lot better:

<h3>Other standards</h3>
<div class="row">
    <div class="col-12">
    <?php
    $query = new WP_Query( [
        'post_type'      => 'page',
        'post_parent'    => 27,
        'posts_per_page' => 100,
        'orderby'        => 'menu_order'
        'order'          => 'ASC'
    ] );
    if ( $query->have_posts() ) {
        while ( $query->have_posts() ) {
            $query->the_post();
            ?>
            <p>TEST</p>
            <?php
        }
        wp_reset_postdata();
    }
    ?>
    </div>
</div>
  • switched from query_posts and wp_reset_query to WP_Query, pretend query_posts doesn’t exist, it causes more issues than it solves and WP_Query is superior in every way
  • Added a wp_rest_postdata inside the if statement after the while loop, now we only cleanup things when there are things to cleanup
  • replace the parameter string with an array of keys and values, a minor optimisation but now no string parsing takes place, are numbers are numbers rather than strings, and we can use more complex parameters such as tax_query etc
  • set posts_per_page to a high value rather than unlimited, sure you might only have 20 or 70 pages, but what if you import a tonne by accident or business requirements change? It’s better to set an unrealistically high number that you know the page and server can handle as the worst case scenario. Fetching more than 100 posts at a time isn’t a good idea, if you need more than 100, consider putting a link to a post archive.
  • I removed the extra PHP opening and closing tags for blocks of PHP that have no template tags inbetween them, this should make the original mistake a lot easier to spot
  • By doing it this way, if you’ve set an opentype font in your editor you’ll get lovely ligatures for the -> and => syntax
  • You could put that array in a variable, then if you needed a 3rd loop you could just change the bit you want instead of creating a new array from scratch

I’d also consider removing the hardcoded post parent number, as the template will break on a site migration using the WP importer, or if that page is deleted and recreated. It also means if you need to set up the site again or locally this template won’t work

So instead here are 3 alternatives:

  • use named pages, and fetch the post via its slug to get the ID, this solves the problem of hardcoded numbers
  • use the children of a named page, this would let you wrap this all in another query loop and automate the titles, adding new pages would add new sections
  • A standards post type with a category taxonomy. Then you could just loop over the terms and query the posts, and you’d get a free paginated archive and URLs