Different Loop for tag pages?

Your code is trying to use if statements to control which if statements are being used, etc, which is meta programming. It will not work, and it can never work.

<?php

if ( is_tag() ) {
    if ( have_posts() ) {
        while ( have_posts() ) {
            the_post(); 
        }
    else { 
        $paged      = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
        $query_args = array( 
            'post_type'         => 'post',
            'post_status'       => array( 'private', 'publish' ),
            'posts_per_page'    => 20,
            'paged'             => $paged,
        ); 
        $the_query  = new WP_Query( $query_args );

        if ( $the_query->have_posts() ) {

            <!-- the new loop -->
        while ( $the_query->have_posts() ) {
            $the_query->the_post(); 
        }

The above code is equivalent to what you wrote, and has the following issues:

  • There’s a HTML comment in the middle of your PHP code, this is invalid syntax and isn’t PHP
  • You never close your first if statement, or your second.
  • Your first post loop doesn’t actually do anything
  • Your else statement is missing a closing brace
  • You attempt to create a brand new query rather than modifying the existing one with the pre_get_posts filter. This implies you’re doing this in a page template and trying to display posts, rather than relying on knowledge of the template hierarchy. Did you know WordPress provides templates for tags categories and custom post types, even down to individual dates and specific categories? Read about the template hierarchy, it will save you a stupendous amount of time, you could be wasting thousands in wasted in billable hours by not knowing about it.

Because of all these syntax errors PHP gives up and sends an error. This is why you get nothing below your header, because the PHP that happens after your header is invalid. To do what you tried to do you would need a preprocessor, which PHP doesn’t have

You stated this template is for the homepage, but that it’s also being used in tag archives, which implies this is actually index.php.

So instead, lets identify 2 problems:

  1. You need to modify what gets shown on the homepage
  2. You need to show something else when on tag archives

Solving Problem 1

Your solution so far has been to ignore what WordPress retrieved from the database and make a second database query. This is expensive and equivalent to this:

You send your PA out every morning to fetch you a cup of tea. You send them to a place 30 minutes away, and every day when they come back you throw the tea on the floor and say “Actually I want a latte”

Suffice to say this is expensive and wastes a lot of time. Your new WP_Query is equivalent to query_posts. People say don’t use query_posts because of what it does, what’s happening here is a slightly more elegant way of doing the same thing, it’s still fundamentally expensive.

Instead, lets use pre_get_posts:

function exclude_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'posts_per_page', '20' );
        $query->set( 'post_status', array( 'private', 'publish' );
    }
}
add_action( 'pre_get_posts', 'exclude_category' );

That filter will modify the query before it happens on your homepage, allowing you to use a standard, normal post loop, rather than a custom WP_Query loop. Pagination will simply work out of the box, and there won’t be any additional queries. This is equivalent to:

Just before the PA goes out to get the cup of tea, you tap them on the shoulder and say “This order’s wrong, sorry about that, can you get me a latte instead?”. The PA gets a latte the first time, no tea is thrown on the floor, and you get your drink a lot quicker

As an aside, index.php is the fallback template. For your homepage, consider using home.php.

Like all filters, this goes in functions.php, not your template.

Solving Problem 2

Use tag.php, it’s as simple as that. Don’t try to use the same template to display multiple things with conditionals everywhere, just follow the template hierarchy and let WordPress do the work