Elegant wp-query markup for repetitive post-type category loops
First off, Wordpress is an awful platform when it comes to separation of business logic from display logic.  If you expect to continue working in it, you can expect to continue to feel the pain that you are feeling.

The thing that concerns me the most about your comments, is that you say you cut/paste this code repeatedly.  That immediately screamw out for putting this code into a widget or function so that it is reusable.  Think if you had a function like:

display_category_list($post_type, $category_name, $show_posts = -1)
{
    // your code
}


This would simplify your main pages to have calls like:

display_category_list('project', 'documentary');
display_category_list('foo', 'bar');


So that could solve the copy/paste problem.



Now let's get into the problem of display templating.  Even working with basic PHP output mechanisms, you can greatly clean up your code, simply by separating out the logic from the HTML in a more reasonable fashion.  You could structure your code like this:

display_category_list($post_type, $category_name, $show_posts = -1)
{
    // Define main section template.
    // You could just as easily include this to keep template
    // in a separate file
    $section_template = &lt;&lt;&lt;'EOT'

&lt;section class='container projects one'&gt;
&lt;div class='inner-w'&gt;
{{list}}
&lt;/div&gt;
&lt;/section&gt;
EOT;

    // list template, again could be included
    $list_template = &lt;&lt;&lt;'EOT'

    &lt;h2 class='category-title'&gt;{{category_name}}&lt;/h2&gt;
    &lt;ul class='project-list'&gt;
    {{items}}
    &lt;/ul&gt;
    &lt;/h2&gt;
EOT;

    // item template
    $item_template = &lt;&lt;&lt;'EOT'

        &lt;li class='project'&gt;
            &lt;a class='link' href='{{link}}'&gt;
                &lt;figure class='poster'&gt;
                    &lt;img src='{{poster}}' alt='{{poster_alt_text}} poster image' /&gt;
                &lt;/figure&gt;
                &lt;h1 class='title'&gt;{{title}}&lt;/h1&gt;
            &lt;/a&gt;
        &lt;/li&gt;
EOT;

    // Actual function logic
    $args = array(
        'post_type' =&gt; $post_type,
        'showposts' =&gt; $show_posts,
        'category_name' =&gt; $category_name,
    );
    $query = new WP_Query($args);

    // put default "no post" content here (this could come from template as well)
    $list_content = '';
    if($query-&gt;have_posts()) {
        $list_content = str_replace('{{category_name}}', $category_name, $list_template);   
        $items = '';
        while ($project_query-&gt;have_posts()) {
            $post-&gt;the_post();
            $link = the_permalink();
            $poster = (get_field('project_poster')) ?
                $image['sizes']['medium'] : 'https://placehold.it/1600x900';
            $poster_alt_text = get_the_title();
            $title = the_field('project_title');
            $template_data = array(
                '{{link}}' =&gt; $link,
                '{{poster}}' =&gt; $poster,
                '{{poster_alt_text}}' =&gt; $poster_alt_text,
                '{{title}}' =&gt; $title
            );
            $items .= str_replace(
                array_keys($template_data),
                array_values($template_data),
                $item_template
            );
            $items .= PHP_EOL;    
        }
        $list_content = str_replace('{{items}}', $items, $list_content);
    }        
    echo str_replace('{{list}}', $list_content, $section_template);            
    wp_reset_postdata();
}


Note how I have moved the HTML into templates defined within nowdoc blocks.  This approach can allow you to easily pull this content out of the function itself into separate template files that are easier to manage.  For example, the function could be rewritten with template-to-variable assignments like this:

$section_template = include('/path/to/section_template.php');


With the template file looking like:

return &lt;&lt;&lt;'EOT'

&lt;section class='container projects one'&gt;
&lt;div class='inner-w'&gt;
{{list}}
&lt;/div&gt;
&lt;/section&gt;
EOT;


This means you could even go so far as to pass template file paths into the function on the fly to switch out templates to be used (or you could have some config settings for template paths that the function uses).  This could totally get you out of having any HTML within the function itself.