Cómo dividir un bucle en múltiples columnas
Si tengo un bucle ejecutándose desde una consulta de categoría como:
<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<ul>
<?php while ($the_query->have_posts()) : $the_query->the_post();?>
<li>.. </li><?php wp_reset_query(); ?>
<?php endwhile; ?>
</ul>
¿Cómo crearía una cláusula if que rompa la lista en un intervalo determinado y comience una nueva? Por ejemplo, en la décima entrada, devolver un </ul>
y comenzar uno nuevo <ul>
en la entrada 11.
Esto es incorrecto pero ilustra mi objetivo:
<?php $count =0;
while($count <=50){
if ($count == 9){
echo "<li><a href='<?php the_permalink(); ?>'>
<?php the_title(); ?></a></li></ul>";
}
elseif ($count == 10){
echo "<ul><li><a href='<?php the_permalink(); ?>'>
<?php the_title(); ?></a></li>";
}
else {
echo "<li><a href='<?php the_permalink(); ?>'><?php the_title(); ?></a></li>";
}
¿Cuál es la forma correcta de incluir esta lógica en el bucle?

Crear columnas para tu consulta y visualización fácil
En los temas probablemente sea más útil tener algo que encaje bien con las etiquetas de plantilla y el loop. Mi primera respuesta no se enfocaba mucho en eso. Además, pensé que era un poco demasiado complicado para una adopción rápida.
Un enfoque más sencillo que se me ocurrió fue extender "el loop" con columnas y llegué a esta solución hasta ahora:
Un objeto WP_Query_Columns "extiende" cualquier consulta estándar de WP con columnas que se pueden iterar fácilmente. El primer parámetro es la variable de consulta y el segundo parámetro es el número de elementos que se mostrarán por columna:
<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<?php foreach(new WP_Query_Columns($the_query, 10) as $column_count) : ?>
<ul>
<?php while ($column_count--) : $the_query->the_post(); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endwhile; ?>
</ul>
<?php endforeach; ?>
Para usarlo, simplemente añade la clase WP_Query_Columns desde este gist a tu functions.php del tema.
Uso avanzado
Si necesitas el número de columna que estás mostrando actualmente (por ejemplo, para algunas clases CSS par/impar), también puedes obtenerlo desde el foreach:
<?php foreach(new WP_Query_Columns($the_query, 10) as $column => $column_count) : ?>
Y el número total de columnas también está disponible:
<?php
$the_columns = new WP_Query_Columns($the_query, 10);
foreach($the_columns as $column => $column_count) :
?>
<h2>Columna <?php echo $column; ?>/<?php echo sizeof($the_columns); ?></h2>
<ul>...
Ejemplo con Twenty Ten
Pude modificar rápidamente el tema Twenty Ten para una prueba y añadir encabezados sobre cualquier loop de esta manera. Se inserta en loop.php, el comienzo es el código del tema:
<?php /* Si no hay posts para mostrar, como en una página de archivo vacía */ ?>
<?php if ( ! have_posts() ) : ?>
<div id="post-0" class="post error404 not-found">
<h1 class="entry-title"><?php _e( 'No encontrado', 'twentyten' ); ?></h1>
<div class="entry-content">
<p><?php _e( 'Disculpas, pero no se encontraron resultados para el archivo solicitado. Quizás buscar ayude a encontrar un post relacionado.', 'twentyten' ); ?></p>
<?php get_search_form(); ?>
</div><!-- .entry-content -->
</div><!-- #post-0 -->
<?php endif; ?>
<!-- WP_Query_Columns -->
<?php
### Necesita WP_Query_Columns --- ver http://wordpress.stackexchange.com/q/9308/178
$query_copy = clone $wp_query; // guardar para restaurar después
foreach( new WP_Query_Columns($wp_query, 3) as $columns_index => $column_count ) : ?>
<ul>
<?php
while ( $column_count-- ) : the_post(); ?>
<li><h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Enlace permanente a %s', 'twentyten' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2></li>
<?php endwhile; ?>
</ul>
<?php endforeach; ?>
<?php $wp_query = $query_copy;?>
<?php
/* Comienza el Loop.
...
Para una respuesta más larga:
(que es básicamente cómo llegué a lo anterior, pero explica mejor cómo resolver realmente el problema con operaciones matemáticas simples. Mi nueva solución es iterar sobre algo pre-calculado.)
Depende un poco de cuánto necesites resolver realmente el problema.
Por ejemplo, si el número de elementos por columna es igual a uno, esto es muy simple:
<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<?php while ($the_query->have_posts()) : $the_query->the_post();?>
<ul>
<li>.. </li>
<ul>
<?php endwhile; wp_reset_query(); ?>
</ul>
Incluso con ese código simple, se puede ver que hay múltiples decisiones que tomar:
- ¿Cuántos elementos hay en una columna?
- ¿Cuántos elementos hay en total?
- ¿Hay que empezar una nueva columna?
- ¿Y hay que terminar una columna?
La última pregunta es bastante interesante para el HTML ya que probablemente quieras envolver no solo los elementos sino también la columna con elementos HTML.
Afortunadamente con código, podemos establecer todo esto en variables y crear código que siempre se ajuste a nuestras necesidades.
Y a veces ni siquiera podemos responder todas las preguntas desde el principio. Por ejemplo, el conteo total de elementos: ¿Hay algunos, varios, un conteo exacto que coincida con un número entero de columnas en total?
Incluso la respuesta de Jan Fabry podría funcionar en algunos casos (como mi ejemplo anterior lo hace para el escenario de un elemento por columna), podrías estar interesado en algo que funcione para cualquier número de elementos devueltos por WP_Query.
Primero para las matemáticas:
//
// ejemplo aritmético:
//
# configuración:
$colSize = 20; // número de elementos en una columna
$itemsTotal = 50; // número de elementos (total)
# cálculo:
$count = 0; // un contador basado en cero
$isStartOfNewColum = 0 === ($count % $colSize); // operación módulo
$isEndOfColumn = ($count && $isStartOfNewColum) || $count === $itemsTotal; // encapsulamiento
Ese código no se ejecuta, así que vamos a convertirlo en un ejemplo de texto simple
//
// ejemplo de texto simple:
//
$column = 0; // inicializar contador de columnas
for($count=0; $count<= $itemsTotal; $count++) {
$isStartOfNewColum = 0 === ($count % $colSize); // módulo
$isEndOfColumn = ($count && $isStartOfNewColum);
$isStartOfNewColum && $column++; // actualizar contador de columnas
if ($isEndOfColumn) {
printf("/Fin de Columna: %d\n", $column-1);
}
if ($isStartOfNewColum) {
printf("<inicio de Columna: %d\n", $column);
}
printf(" * elemento %d\n", $count);
}
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
printf("/Fin de Columna: %d\n", $column);
}
printf("Terminado. Número total de Columnas: %d.\n", $column);
Esto realmente se ejecuta y ya produce alguna salida:
<inicio de Columna: 1
* elemento 0
* elemento 1
* elemento 2
* elemento 3
...
* elemento 17
* elemento 18
* elemento 19
/Fin de Columna: 1
<inicio de Columna: 2
* elemento 20
* elemento 21
* elemento 22
...
* elemento 37
* elemento 38
* elemento 39
/Fin de Columna: 2
<inicio de Columna: 3
* elemento 40
* elemento 41
* elemento 42
...
* elemento 48
* elemento 49
* elemento 50
/Fin de Columna: 3
Terminado. Número total de Columnas: 3.
Esto simula bastante bien cómo podría verse en una plantilla de WordPress:
//
// ejemplo de WordPress:
//
$count = 0; // inicializar contador de elementos
$column = 0; // inicializar contador de columnas
$colSize = 10; // tamaño de columna de diez esta vez
$the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');
$itemsTotal = $the_query->post_count;
?>
<?php while ($the_query->have_posts()) : $the_query->the_post();?>
<?php
# variables de visualización de columnas
$isStartOfNewColum = 0 === ($count % $colSize); // módulo
$isEndOfColumn = ($count && $isStartOfNewColum);
$isStartOfNewColum && $column++; // actualizar contador de columnas
if ($isEndOfColumn) {
print('</ul>');
}
if ($isStartOfNewColum) {
printf('<ul class="col-%d">', $column);
}
?>
<li> ... haz tu día ...
</li>
<?php endwhile; ?>
<?php
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
print('</ul>');
}
// No necesitas hacer esto en cada loop, solo una vez al final debería ser suficiente
wp_reset_query();
?>
(No he ejecutado el último ejemplo en un entorno WP, pero debería ser al menos sintácticamente correcto.)

Esta es más una pregunta general de programación, pero aquí está la idea básica:
<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<ul>
<?php
$post_counter = 0;
while ($the_query->have_posts()) :
$the_query->the_post();
$post_counter++;
?>
<li>.. </li>
<?php
if ( 0 == $post_counter % 10 ) {
echo '</ul><ul>';
}
endwhile;
?>
</ul>
<?php
// No necesitas hacer esto en cada ciclo, solo una vez al final es suficiente
wp_reset_query();
?>

La operación de módulo es básicamente la respuesta matemática. Pero tu ejemplo carece de salida HTML semántica. He propuesto algo similar en mi respuesta, como puedes imaginar, tomó un poco más de tiempo ;)

wp_reset_query();
no está relacionado con la variable $the_query. Esto no es necesario en absoluto, ¿verdad?

@hakre: $the_query->the_post()
sobrescribirá la variable global $post
, y wp_reset_query()
restaura esto (llamando a wp_reset_postdata()
- ¿que también podría ser suficiente por sí solo?).

Vale, de alguna manera mezclé wp_query y post un poco, pensé que haría algo con $wp_query
pero en el ejemplo se usó $the_query
. Sin embargo, estaba equivocado, lo agregaré a mi segunda respuesta para que sea más completo.

No es necesario crear una variable separada para el conteo, ya que la variable de consulta ya lo cuenta en: $wp_query->current_post
. Además, debes tener en cuenta la última entrada en la lista para que no tengas <ul></ul>
vacíos en tu marcado.
<?php
$the_query = new WP_Query('showposts=21&orderby=title&order=asc');
echo "<ul>";
while ($the_query->have_posts()) :
$the_query->the_post();
echo "<li>{$the_query->current_post}</li>";
// Nota que el post ya está contado en la variable $the_query->current_post cuando está en el bucle. Suma uno para traducir el conteo de arrays a conteos reales.
// El ejemplo de Jan no tenía en cuenta la última entrada en la lista. No queremos <ul> vacíos por ahí
if ((($the_query->current_post+1) % 10 == 0) && ($the_query->current_post+1 !== count($the_query->posts))):
echo "</ul><ul>";
endif;
endwhile;
echo "</ul>";
?>

Genial, me gusta la adición porque el ´<ul></ul>` vacío es solo para 0 publicaciones ahora (pero para esas aún lo es) - pero por lo que he aprendido hoy, esa forma es la más pequeña sin introducir una nueva función.

Buena adición. Veo que WP_Query
también tiene una variable $post_count
, puedes usar eso en lugar de count($the_query->posts)
. Zac, puedes "desaceptar" mi respuesta y aceptar otra si resolvió mejor tu problema.

Añade la función get_columns_array()
a tu archivo function.php. Luego podrás iterar fácilmente sobre tus columnas:
En tu tema, puedes hacer un bucle foreach sobre las columnas:
<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<?php foreach(get_columns_array($post_count) as $column_count) : ?>
<ul>
<?php while ($column_count--) : $the_query->the_post(); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endwhile; ?>
</ul>
<?php endforeach; wp_reset_postdata(); ?>
Establezco el tamaño predeterminado de una columna en 10. Puedes usar el segundo parámetro para definir el tamaño de una columna por tu cuenta. Por ejemplo, a 7: get_columns_array($post_count, 7);
.

Aquí hay otro enfoque que puedes tomar:
$article = 0;
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php $article = $article + 1; ?>
<?php if ($article % 3 == 1) echo '<div class="row-fluid">'; ?>
<div class="span4">
<h2><a href="<?php esc_url( the_permalink() ); ?>" title="Enlace permanente a <?php the_title(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
</div><!--/span-->
<?php if ($article % 3 == 0) echo '</div><!--/row-->'; ?>
<?php endwhile;?>
<?php else: ?>
<h2>...</h2>
<?php endif; ?>
