Por que devo colocar se (have_posts ()), enquanto (have_posts ()) não é suficiente?

22

Eu tenho uma pergunta sobre "o 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; ?>

Código extraído da página The Loop WordPress Codex .

Por que devo colocar ifparte? Parece que se houver whileloop, funciona bem.

Em que caso o problema ocorre se não houver ifdeclaração?

Editar

Aceitei a resposta de @ Chip. mas honestamente dizendo que preciso apenas da última parte.

Agora sei o que queria saber da minha pergunta.

ifA instrução é apenas quando necessário, se você deseja colocar um cabeçalho ou rodapé que deve ser gravado apenas uma vez. se você não usar o "wrapper", a ifinstrução não será necessária.

ferros e areias
fonte
2
Votei antes de ler the_content, the_title é decisivo!
Brasofilo 9/10
Excelente (final) edição. A maioria das pessoas usa o if e while diretamente um após o outro sem nunca usar outro. Provavelmente por causa de copiar e colar.
Herbert Van-Vliet

Respostas:

29

O carregador de modelos do WordPress incluirá o arquivo de modelo contextual apropriado em várias circunstâncias, mesmo se a consulta para esse contexto não retornar postagens. Por exemplo:

  • O principal índice de postagens do blog
  • Índice do arquivo de categorias (a categoria existe, mas não possui postagens)
  • Índice de archive de tags (a tag existe, mas não possui postagens)
  • Índice do arquivo de autor (o autor existe, mas não possui postagens)
  • Índice de Resultados da Pesquisa

Portanto, nesses casos, o arquivo de modelo apropriado será carregado, mas nenhuma postagem será exibida, porque a consulta não retornará nenhuma postagem.

Exemplos de prova de conceito:

Portanto, nesses contextos, é útil que o arquivo de modelo inclua a if ( have_posts() )condicional.

Em outros contextos, o arquivo de modelo nunca será carregado se a consulta não retornar postagens. Por exemplo:

  • Postagem em blog único
  • Página estática

Nesses contextos, if ( have_posts() )provavelmente é desnecessário.

Editar

Entendo que a consulta é invocada pelo the_post (), certo? E se while (have_posts ()) existir, a consulta nunca ocorrerá se não houver postagem.

Para entender o que está acontecendo, você deve observar a ordem das ações do WordPress . Começando com wp_loaded(e omitindo alguns para maior clareza):

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

Então, o que está acontecendo e em que ordem?

  • A consulta é invocada:
    • parse_query
    • pre_get_posts
    • wp
  • O modelo está selecionado:
    • template_redirect
  • O modelo é carregado / produzido. As seguintes ações são disparadas pelo modelo :
    • get_header
    • wp_head
    • the_post
    • dynamic_sidebar
    • get_footer
    • wp_footer

Assim, the_postacionado the_post(), acontece muito depois que a consulta é analisada, as postagens são buscadas e o modelo é carregado.

Sou muito grato por você ter fornecido muitas informações que eu não sabia, mas não foi isso que pedi.

Ah, mas acredito que é exatamente o que você pediu.

A verdadeira questão é: o que é um retorno de consulta válido ? Para contextos como o índice de arquivamento de categoria, a consulta é válida e o modelo de categoria é carregado, se o ID da categoria consultada existir, mesmo se não houver postagens atribuídas a essa categoria .

Por quê? Como a consulta que está sendo analisada é (IIRC) &cat={ID}- que é uma consulta válida mesmo que não haja postagens atribuídas a essa categoria e, portanto, não resulta em 404 na análise.

Nesse caso, você obtém uma consulta válida e um arquivo de modelo carregado, mas nenhuma postagem . Assim, if ( have_posts() ), é, de fato relevante. Novamente, aqui está um exemplo: a categoria existe, mas não possui postagens atribuídas. O arquivo de modelo de categoria é carregado, com if ( have_posts() )retornofalse .

Isso não será verdadeiro para consultas que incluem uma variável de postagem ( &p={ID}), como postagens de blog únicas e páginas estáticas, porque a postagem realmente não existe e, quando analisada, a consulta não retornará um objeto válido.

Editar 2

Se eu entendi corretamente se não há if (have_posts ()) em um modelo de categoria e a categoria não possui post, ele retorna 404.php, mesmo que deva retornar category-sample.php sem post. Isso esta certo?

Não. Lembre-se: o modelo está selecionado em template_redirect. Portanto, se a consulta for válida, o arquivo de modelo apropriado será carregado. Se a consulta não for válida, o modelo 404 será carregado.

Assim, uma vez que um modelo é carregado - por exemplo, o modelo de categoria - depois que o loop é gerado, o modelo não muda .

Veja novamente a ordem das ações:

  • parse_query
  • pre_get_posts
  • wp
  • template_redirect- o modelo é escolhido e carregado aqui. Este é o ponto do modelo sem retorno . O modelo não pode ser alterado após esse ponto.
  • ...
  • the_post- postdata é configurado aqui, como parte da chamada de loop. Isso é chamado dentro do modelo e o modelo não muda com base nos dados disponíveis no objeto de consulta

Edição final

E estou alegando que, embora verifique a existência de postagens, por que devo executar o mesmo teste duas vezes. Essa é a minha pergunta desde o primeiro ponto que venho perguntando apenas sobre isso.

E com isso, finalmente entendo: o tempo todo, sua pergunta não teve nada a ver com o WordPress , ou o Loop do WordPress . Você está perguntando sobre agrupar qualquer whileloop PHP arbitrário dentro de um ifcondicional que verifica a mesma condição.

Essa pergunta está fora do escopo da WPSE, mas vou explicar brevemente:

Uma ifcondicional é uma avaliação binária: é uma trueou ou false, e o que acontece dentro dessa condicional é executado uma vez .

Um whilecondicional é um loop : permanece verdadeiro por um período discreto, com base em algum tipo de contador; e o que acontece dentro desse condicional é executado várias vezes - uma vez para cada iteração do contador.

Então, digamos que você queira gerar uma lista não ordenada de itens, se a lista de itens estiver preenchida. Se você usar um whileloop e omitir o ifwrapper, sua marcação ficará assim:

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

E se list_of_things()estivesse vazio, a saída renderizada seria:

<ul>
</ul>

O que deixa a marcação desnecessária (e inválida).

Mas se você adicionar um ifwrapper condicional, poderá fazer o seguinte:

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

E se list_of_things()estivesse vazio, nenhuma marcação seria emitida.

Esse é apenas um exemplo. Existem muitos usos para esse ifwrapper condicional, e o ifwrapper condicional serve a um propósito totalmente diferente do whileloop.

Chip Bennett
fonte
2
Nos meus modelos singulares de postagem / página, há muito tempo que uso apenas the_post();porque também whileé desnecessário. +1 para a exaustividade das informações.
gmazzap
@ GM Possivelmente remover a if( have_posts() )declaração faz sentido (é o que estou tentando descobrir), mas não use apenas the_post()em páginas singulares!
Sunyatasattva 12/10
@ChipBennett Considerando tudo, você acha que é seguro remover a if( have_post() )condição antes do ciclo completo no contexto dos arquivos single-*.phpe page-*.phpmodelo?
Sunyatasattva 12/10
1
"Seguro" realmente não tem significado definitivo nesse contexto.
Chip Bennett
10

É realmente impossível melhorar a resposta de Chip, mas apenas direto ao ponto:

Use a ifparte se quiser que algo diferente apareça quando não houver postagens . Isso é particularmente útil, por exemplo, em uma página de arquivo de data ou categoria. Se alguém navega para uma página que não possui postagens, é bom ter uma mensagem dizendo isso, em vez de simplesmente nada aparecer, porque o loop nunca é executado.

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;
Tom Auger
fonte
E isso é tudo que você precisa saber.
Herbert Van-Vliet
0

Pode haver algumas considerações que não estão incluídas nas respostas até o momento. Não é recomendável omitir a instrução if.

A instrução if é comumente usada para:

  • produz algo parecido no posts foundcom o de indicar que a categoria em questão não possui artigos atribuídos a ela.
  • para decidir se o html circundante (como um ul) deve ser produzido antes e depois dos artigos.

E se um novo gancho for adicionado?

Outra possível questão de não usar a instrução if é que, se a equipe do wordpress decidir adicionar um novo gancho que seja acionado na primeira $wp_query->have_posts()chamada, ele será acionado na hora errada. E se isso causar um comportamento inesperado, seria sua culpa por não seguir as especificações corretamente.

Outros desenvolvedores esperam ver uma estrutura específica para o loop wordpress

Suponho que outros desenvolvedores esperem ver todo o loop do wordpress. Talvez seja uma má idéia tê-los procurando por uma declaração if que não esteja lá.

RMo
fonte
-1

Eu vejo isso como uma questão fundamental da teoria da estrutura de controle. O bloco fechado no loop while não é executado nem uma vez se a condição (have_posts ()) for avaliada como falsa na primeira vez.

Portanto, o objetivo do if ( have_posts() )loop do WordPress é apenas executar a função have_posts () uma vez antes da condição while ser avaliada. Se have_posts()não tem efeitos colaterais, então if ( have_posts() )é totalmente inútil. Se have_posts()tiver efeitos colaterais, você pode simplificar da seguinte maneira:

<?php have_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
Schparky
fonte
3
Essa simplificação é PHP inválido, você tem uma instrução else que não possui uma declaração if anexada. Na melhor das hipóteses, é difícil de ler
Tom J Nowell
1
O ifestá lá por causa do elsedepois dele. Nenhuma outra razão. Se não houver postagens, é melhor exibir uma boa mensagem "sem postagens" do que não exibir nada.
Otto