Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a question about "the loop".

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>

Code taken from The Loop WordPress Codex page.

Why should I put if part? It seems like if there is while loop, works fine.

In what case problem occurs if there is no if statement?

Edit

I accepted @Chip's answer. but honestly saying I need only last part.

I know now what I wanted to know from my question.

if statement is only when necessary, if you want to put a header or footer that should be write only once. if you don't use the "wrapper", then if statement is not necessary.

share|improve this question
1  
I voted up before reading the_content, the_title is decisive! –  brasofilo Oct 9 '13 at 10:36
add comment

2 Answers

up vote 17 down vote accepted

The WordPress template loader will include the appropriate contextual template file in many circumstances, even if the query for that context returns no posts. For example:

  • The Main Blog Posts Index
  • Category Archive Index (Category exists, but has no posts)
  • Tag Archive Index (Tag exists, but has no posts)
  • Author Archive Index (Author exists, but has no posts)
  • Search Results Index

Thus, in these cases, the appropriate template file will be loaded, but no posts will be output, because the query returns no posts.

Proof-of-concept examples:

So, in these contexts, it is useful for the template file to include the if ( have_posts() ) conditional.

In other contexts, the template file will never be loaded if the query returns no posts. For example:

  • Single blog post
  • Static page

In these contexts, if ( have_posts() ) is probably unnecessary.

Edit

I understand the query is invoked by the_post(), right? And if while(have_posts()) exist, the query is never occurs if there is no post.

To understand what's going on, you have to look at the order of WordPress actions. Starting with wp_loaded (and omitting some for clarity):

  • wp_loaded
  • parse_request
  • send_headers
  • parse_query
  • pre_get_posts
  • wp
  • template_redirect
  • get_header
  • wp_head
  • the_post
  • wp_footer

So, what's happening, and in what order?

  • The query is invoked:
    • parse_query
    • pre_get_posts
    • wp
  • The template is selected:
    • template_redirect
  • The template is loaded/output. The following actions are fired by the template:
    • get_header
    • wp_head
    • the_post
    • dynamic_sidebar
    • get_footer
    • wp_footer

So, the_post, fired by the_post(), happens long after the query is parsed, posts are fetched, and the template is loaded.

I'm very grateful that you give a lot of information that I didn't know, but this is not what I asked.

Oh, but I believe that it is exactly what you asked.

The real question is: what is a valid query return? For contexts such as the category archive index, the query is valid, and the category template is loaded, if the queried category ID exists, even if there are no posts assigned to that category.

Why? Because the query being parsed is (IIRC) &cat={ID} - which is a valid query even if there are no posts assigned to that category, and thus doesn't result in a 404 upon parsing.

In that case, you get a valid query, and a template file loaded, but no posts. Thus, if ( have_posts() ), is, in fact relevant. Again, here is an example: category exists, but has no posts assigned. Category template file is loaded, with if ( have_posts() ) returning false.

This won't hold true for queries that include a post variable (&p={ID}) such as single blog posts and static pages, because the post won't actually exist, and when parsed, the query will not return a valid object.

Edit 2

If I rightly understand if there is no if(have_posts()) in a category template and the category have no post, then it return 404.php, even though it should be return category-sample.php without post. Is that right?

No. Remember: the template is selected at template_redirect. So if the query if valid, then the appropriate template file is loaded. If the query is not valid, then the 404 template is loaded.

So, once a template is loaded - e.g. the category template - once the loop is output, the template does not change.

Look again at the order of actions:

  • parse_query
  • pre_get_posts
  • wp
  • template_redirect - template is chosen and loaded here. This is the template point of no return. The template cannot change after this point.
  • ...
  • the_post - postdata is setup here, as part of the loop call. This is called inside the template, and the template does not change based on available data in the query object

Final Edit

And I'am claiming that while checks existence of posts, why should I run the same test twice. That is my question from first point I've been asking only about that.

And with that, I finally understand: all along, your question had nothing to do with WordPress, or the WordPress Loop. You're asking about wrapping any arbitrary PHP while loop inside an if conditional that checks the same condition.

That question is outside the scope of WPSE, but I'll briefly explain:

An if conditional is a binary evaluation: it's either true or false, and what happens inside of that conditional is executed once.

A while conditional is a loop: it remains true for some discrete period, based on some sort of counter; and what happens inside of that conditional is executed several times - once for each iteration of the counter.

So, let's say that you want to output an unordered list of things, if the list of things is populated. If you use a while loop, and omit the if wrapper, your markup would look like this:

<ul>
<?php while ( list_of_things() ) : ?>
    <li><?php the_list_item(); ?></li>
<?php endwhile; ?>
</ul>

And if list_of_things() was empty, the rendered output would be:

<ul>
</ul>

Which leaves unnecessary (and invalid) markup.

But if you add in an if conditional wrapper, you can do this:

<?php if ( list_of_things() ) : ?>
    <ul>
    <?php while ( list_of_things() ) : ?>
        <li><?php the_list_item(); ?></li>
    <?php endwhile; ?>
    </ul>
<?php endif; ?>

And if list_of_things() was empty, no markup at all would be output.

That's just one example. There are lots of uses for that if conditional wrapper, and the if conditional wrapper serves an entirely different purpose than the while loop.

share|improve this answer
2  
In my singular post/page templates, since a long time, I use only the_post(); because also the while is unnecessary. +1 for the completeness of informations. –  G. M. Oct 9 '13 at 17:00
    
@G.M. Possibly removing the if( have_posts() ) statement makes sense (that's what I am trying to find out), but don't just use the_post() in singular pages! –  Sunyatasattva Oct 12 '13 at 20:53
    
@ChipBennett All considered, do you think it is safe to remove the if( have_post() ) condition before the full loop in the context of single-*.php and page-*.php template files? –  Sunyatasattva Oct 12 '13 at 20:55
    
"Safe" really has no definitive meaning in this context. –  Chip Bennett Oct 12 '13 at 21:05
add comment

It's really impossible to improve on Chip's answer, but just to cut to the chase:

Use the if part if you want to have something different show up when there are no posts. This is particularly useful, for example, on a date or category archive page. If someone navigates to a page that has no posts, it's nice to have a message that says so, rather than just nothing appearing at all, because the loop never gets executed.

if ( have_posts() ):
  // Yep, we have posts, so let's loop through them.
  while ( have_posts() ) : the_post();
  // do your loop
  endwhile;
else :
  // No, we don't have any posts, so maybe we display a nice message
  echo "<p class='no-posts'>" . __( "Sorry, there are no posts at this time." ) . "</p>";
endif;
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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