¿Por qué debo poner if(have_posts()), no es suficiente con while(have_posts())?

9 oct 2013, 11:32:22
Vistas: 51.2K
Votos: 26

Tengo una pregunta sobre "el Loop".

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Lo sentimos, ninguna entrada coincide con tus criterios.'); ?></p>
<?php endif; ?>

Código tomado de la página del Codex de WordPress sobre el Loop.

¿Por qué debería poner la parte del if? Parece que si existe el bucle while, funciona bien.

¿En qué caso ocurre un problema si no hay una declaración if?

Edición

Acepté la respuesta de @Chip, pero siendo honesto solo necesitaba la última parte.

Ahora sé lo que quería saber de mi pregunta.

La declaración if solo es necesaria cuando quieres poner un encabezado o pie de página que debe escribirse una sola vez. Si no usas el "envoltorio", entonces la declaración if no es necesaria.

2
Comentarios

Voté positivo antes de leer the_content, ¡the_title es decisivo!

brasofilo brasofilo
9 oct 2013 13:36:51

Edición (final) excelente. La mayoría de la gente usa el if y while directamente uno tras otro sin usar nunca un else. Probablemente debido al copiar y pegar.

Herbert Van-Vliet Herbert Van-Vliet
5 mar 2018 04:59:10
Todas las respuestas a la pregunta 4
4
33

El cargador de plantillas de WordPress incluirá el archivo de plantilla contextual apropiado en muchas circunstancias, incluso si la consulta para ese contexto no devuelve publicaciones. Por ejemplo:

  • El Índice Principal de Publicaciones del Blog
  • Índice de Archivo de Categoría (La categoría existe, pero no tiene publicaciones)
  • Índice de Archivo de Etiqueta (La etiqueta existe, pero no tiene publicaciones)
  • Índice de Archivo de Autor (El autor existe, pero no tiene publicaciones)
  • Índice de Resultados de Búsqueda

Por lo tanto, en estos casos, se cargará el archivo de plantilla apropiado, pero no se mostrarán publicaciones, porque la consulta no devuelve ninguna.

Ejemplos de prueba de concepto:

Entonces, en estos contextos, es útil que el archivo de plantilla incluya el condicional if ( have_posts() ).

En otros contextos, el archivo de plantilla nunca se cargará si la consulta no devuelve publicaciones. Por ejemplo:

  • Publicación única de blog
  • Página estática

En estos contextos, if ( have_posts() ) probablemente sea innecesario.

Edición

Entiendo que la consulta se invoca mediante the_post(), ¿correcto? Y si existe while(have_posts()), la consulta nunca ocurre si no hay publicaciones.

Para entender lo que está pasando, debes mirar el orden de las acciones de WordPress. Comenzando con wp_loaded (y omitiendo algunas para mayor claridad):

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

Entonces, ¿qué está pasando y en qué orden?

  • Se invoca la consulta:
    • parse_query
    • pre_get_posts
    • wp
  • Se selecciona la plantilla:
    • template_redirect
  • Se carga/muestra la plantilla. Las siguientes acciones se disparan por la plantilla:
    • get_header
    • wp_head
    • the_post
    • dynamic_sidebar
    • get_footer
    • wp_footer

Por lo tanto, the_post, disparado por the_post(), ocurre mucho después de que se analiza la consulta, se obtienen las publicaciones y se carga la plantilla.

Estoy muy agradecido de que proporciones mucha información que no conocía, pero esto no es lo que pregunté.

Oh, pero creo que es exactamente lo que preguntaste.

La verdadera pregunta es: ¿qué es un retorno de consulta válido? Para contextos como el índice de archivo de categoría, la consulta es válida y se carga la plantilla de categoría si el ID de la categoría consultada existe, incluso si no hay publicaciones asignadas a esa categoría.

¿Por qué? Porque la consulta que se está analizando es (si mal no recuerdo) &cat={ID}, que es una consulta válida incluso si no hay publicaciones asignadas a esa categoría, y por lo tanto no resulta en un 404 al analizarse.

En ese caso, obtienes una consulta válida y un archivo de plantilla cargado, pero sin publicaciones. Por lo tanto, if ( have_posts() ) es, de hecho relevante. Nuevamente, aquí hay un ejemplo: la categoría existe, pero no tiene publicaciones asignadas. Se carga el archivo de plantilla de categoría, con if ( have_posts() ) devolviendo false.

Esto no será válido para consultas que incluyan una variable de publicación (&p={ID}), como publicaciones únicas de blog y páginas estáticas, porque la publicación no existirá realmente, y cuando se analice, la consulta no devolverá un objeto válido.

Edición 2

Si entiendo correctamente, si no hay if(have_posts()) en una plantilla de categoría y la categoría no tiene publicaciones, entonces devuelve 404.php, aunque debería devolver category-sample.php sin publicaciones. ¿Es correcto?

No. Recuerda: la plantilla se selecciona en template_redirect. Entonces, si la consulta es válida, se carga el archivo de plantilla apropiado. Si la consulta no es válida, se carga la plantilla 404.

Entonces, una vez que se carga una plantilla (por ejemplo, la plantilla de categoría), una vez que se muestra el bucle, la plantilla no cambia.

Mira nuevamente el orden de las acciones:

  • parse_query
  • pre_get_posts
  • wp
  • template_redirect - la plantilla se elige y se carga aquí. Este es el punto de no retorno de la plantilla. La plantilla no puede cambiar después de este punto.
  • ...
  • the_post - los datos de la publicación se configuran aquí, como parte de la llamada del bucle. Esto se llama dentro de la plantilla, y la plantilla no cambia según los datos disponibles en el objeto de consulta

Edición Final

Y estoy afirmando que while verifica la existencia de publicaciones, ¿por qué debería ejecutar la misma prueba dos veces? Esa es mi pregunta desde el primer punto. Solo he estado preguntando sobre eso.

Y con eso, finalmente entiendo: todo este tiempo, tu pregunta no tenía nada que ver con WordPress o el Bucle de WordPress. Estás preguntando sobre envolver cualquier bucle while de PHP arbitrario dentro de un condicional if que verifica la misma condición.

Esa pregunta está fuera del alcance de WPSE, pero explicaré brevemente:

Un condicional if es una evaluación binaria: es true o false, y lo que sucede dentro de ese condicional se ejecuta una vez.

Un condicional while es un bucle: permanece verdadero durante un período discreto, basado en algún tipo de contador; y lo que sucede dentro de ese condicional se ejecuta varias veces, una vez por cada iteración del contador.

Entonces, digamos que deseas mostrar una lista desordenada de elementos, si la lista de elementos está poblada. Si usas un bucle while y omites el envoltorio if, tu marcado se verá así:

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

Y si list_of_things() está vacío, la salida renderizada será:

<ul>
</ul>

Lo que deja marcado innecesario (e inválido).

Pero si agregas un envoltorio condicional if, puedes hacer esto:

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

Y si list_of_things() está vacío, no se mostrará ningún marcado.

Ese es solo un ejemplo. Hay muchos usos para ese envoltorio condicional if, y el envoltorio condicional if sirve para un propósito completamente diferente que el bucle while.

9 oct 2013 17:02:05
Comentarios

En mis plantillas de publicaciones/páginas individuales, desde hace mucho tiempo, solo uso the_post(); porque el while también es innecesario. +1 por la completitud de la información.

gmazzap gmazzap
9 oct 2013 20:00:59

@G.M. Posiblemente eliminar la declaración if( have_posts() ) tenga sentido (eso es lo que estoy tratando de averiguar), pero ¡no solo uses the_post() en páginas individuales!

Sunyatasattva Sunyatasattva
12 oct 2013 23:53:37

@ChipBennett Considerando todo, ¿crees que es seguro eliminar la condición if( have_post() ) antes del bucle completo en el contexto de los archivos de plantilla single-*.php y page-*.php?

Sunyatasattva Sunyatasattva
12 oct 2013 23:55:00

"Seguro" realmente no tiene un significado definitivo en este contexto.

Chip Bennett Chip Bennett
13 oct 2013 00:05:38
1
11

Es realmente imposible mejorar la respuesta de Chip, pero para ir al grano:

Usa la parte del if si deseas mostrar algo diferente cuando no hay publicaciones. Esto es particularmente útil, por ejemplo, en una página de archivo por fecha o categoría. Si alguien navega a una página que no tiene publicaciones, es bueno mostrar un mensaje que lo indique, en lugar de no mostrar nada, porque el bucle nunca se ejecuta.

if ( have_posts() ):
  // Sí, tenemos publicaciones, así que vamos a recorrerlas.
  while ( have_posts() ) : the_post();
  // haz tu bucle
  endwhile;
else :
  // No, no tenemos ninguna publicación, así que tal vez mostramos un mensaje amigable
  echo "<p class='no-posts'>" . __( "Lo sentimos, no hay publicaciones en este momento." ) . "</p>";
endif;
16 oct 2013 04:18:26
Comentarios

Y esto es todo lo que uno necesita saber.

Herbert Van-Vliet Herbert Van-Vliet
19 may 2018 00:08:22
0

Puede haber algunas consideraciones que no están incluidas en las respuestas hasta ahora. No se recomienda omitir la sentencia if.

La sentencia if se usa comúnmente para:

  • mostrar algo como no se encontraron publicaciones para indicar que la categoría en cuestión no tiene artículos asignados.
  • decidir si el HTML circundante (como un ul) debe mostrarse antes y después de los artículos.

¿Qué pasa si se agrega un nuevo hook?

Otro posible problema de no usar la sentencia if es que si el equipo de WordPress decidiera agregar un nuevo hook que se active en la primera llamada a $wp_query->have_posts(), se activaría en el momento incorrecto. Y si eso causa un comportamiento inesperado, sería tu culpa por no seguir las especificaciones correctamente.

Otros desarrolladores esperan ver una estructura específica para el loop de WordPress

Supongo que otros desarrolladores esperan ver el loop completo de WordPress. Así que tal vez sea una mala idea hacer que busquen una sentencia if que no está ahí.

28 nov 2019 13:24:39
2
-1

Veo esto como una cuestión fundamental de la teoría de estructuras de control. El bloque encerrado dentro del bucle while no se ejecuta ni una sola vez si la condición (have_posts()) se evalúa como falsa la primera vez.

Por lo tanto, el propósito de if ( have_posts() ) en el bucle de WordPress es solo ejecutar la función have_posts() una vez antes de evaluar la condición while. Si have_posts() no tiene efectos secundarios, entonces el if ( have_posts() ) es completamente innecesario. Si have_posts() sí tiene efectos secundarios, podrías simplificarlo de la siguiente manera:

<?php have_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Lo sentimos, no hay publicaciones que coincidan con tus criterios.'); ?></p>
<?php endif; ?>
24 oct 2014 01:59:17
Comentarios

Esa simplificación no es PHP válido, tienes una declaración else que no está asociada a ninguna declaración if. Como mucho, es difícil de leer

Tom J Nowell Tom J Nowell
24 oct 2014 02:27:59

El if está ahí debido al else que viene después. Ninguna otra razón. Si no hay posts, entonces mostrar un mensaje amigable de "no hay posts" es mejor que no mostrar nada.

Otto Otto
24 oct 2014 03:13:09