0

I have a theme that uses one template file to render the index of the blog, the loop is basic:

if ( have_posts() ) : while ( have_posts() ) : the_post(); 

I want to use another custom loop for all my is_tag( '' ) pages.

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(); 

}

This doesn't work at all. It renders everything below header blank. Any ideas how I can do this in a simple way?

EDIT: I understand is_tag() might not work outside the loop is this why this isn't working? What is the good solution?

1
  • 1
    You should use an editor that checks for PHP syntax errors and highlights them, you never close your if/while statements. Not that what you're trying to do will work, you can't conditionally conditional things like that
    – Tom J Nowell
    Mar 3 '16 at 20:15
1

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

3
  • Where do you see that is_tag() should be used inside the loop? This Conditional Tag checks if a Tag archive page is being displayed. +1 for very helpful answer though.
    – Howdy_McGee
    Mar 3 '16 at 20:34
  • 1
    Thanks for all the help guys, i used Tom J Nowell second solution to simply call the tag.php instead, i had to make some modifications to the theme for this to work but it works nicely. Mar 3 '16 at 20:42
  • @Howdy_McGee ah true, I'll edit
    – Tom J Nowell
    Mar 3 '16 at 21:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.