Come dividere un loop in più colonne
Se ho un loop che viene eseguito da una query di categoria come:
<?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>
Come posso creare una clausola if che interrompa la lista a un determinato intervallo e ne inizi una nuova? Per esempio, al decimo post, restituire un </ul>
e iniziarne uno nuovo <ul>
all'undicesimo.
Questo è scorretto ma illustra il mio obiettivo:
<?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>";
}
Qual è il modo corretto per includere questa logica nel loop?

Crea colonne per la tua query e visualizzazione semplice
Nei temi è probabilmente più utile avere qualcosa che si adatti bene ai tag del template e al loop. La mia prima risposta non si concentrava molto su questo. Inoltre pensavo fosse un po' troppo complicato per un'adozione rapida.
Un approccio più semplice che mi è venuto in mente era estendere "il loop" con le colonne e sono arrivato a questa soluzione finora:
Un oggetto WP_Query_Columns "estende" qualsiasi query standard di WP con colonne che possono essere facilmente iterate. Il primo parametro è la variabile della query e il secondo parametro è il numero di elementi da visualizzare per colonna:
<?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; ?>
Per usarlo, basta aggiungere la classe WP_Query_Columns da questo gist al tuo file functions.php del tema.
Utilizzo avanzato
Se hai bisogno del numero della colonna che stai attualmente visualizzando (ad esempio per alcune classi CSS even/odd), puoi ottenerlo anche dal foreach:
<?php foreach(new WP_Query_Columns($the_query, 10) as $column => $column_count) : ?>
E anche il numero totale di colonne è disponibile:
<?php
$the_columns = new WP_Query_Columns($the_query, 10);
foreach($the_columns as $column => $column_count) :
?>
<h2>Colonna <?php echo $column; ?>/<?php echo sizeof($the_columns); ?></h2>
<ul>...
Esempio con Twenty Ten
Ho potuto modificare rapidamente il tema Twenty Ten per un test e aggiungere intestazioni sopra qualsiasi loop in questo modo. È inserito in loop.php, l'inizio è il codice del tema:
<?php /* Se non ci sono post da visualizzare, come una pagina di archivio vuota */ ?>
<?php if ( ! have_posts() ) : ?>
<div id="post-0" class="post error404 not-found">
<h1 class="entry-title"><?php _e( 'Non trovato', 'twentyten' ); ?></h1>
<div class="entry-content">
<p><?php _e( 'Spiacenti, ma non sono stati trovati risultati per l\'archivio richiesto. Forse una ricerca può aiutare a trovare un post correlato.', 'twentyten' ); ?></p>
<?php get_search_form(); ?>
</div><!-- .entry-content -->
</div><!-- #post-0 -->
<?php endif; ?>
<!-- WP_Query_Columns -->
<?php
### Necessita WP_Query_Columns --- vedi http://wordpress.stackexchange.com/q/9308/178
$query_copy = clone $wp_query; // salva per ripristinare dopo
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__( 'Permalink 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
/* Inizia il Loop.
...
Per una risposta più lunga:
(che è fondamentalmente come sono arrivato alle cose sopra, ma spiega meglio come risolvere effettivamente il problema con semplici operazioni matematiche. La mia nuova soluzione è iterare su qualcosa di pre-calcolato.)
Dipende un po' da quanto hai effettivamente bisogno di risolvere il problema.
Ad esempio, se il numero di elementi per colonna è uguale a uno, questo è molto semplice:
<?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>
Anche con questo semplice codice, si può vedere che ci sono diverse decisioni da prendere:
- Quanti elementi ci sono in una colonna?
- Quanti elementi ci sono in totale?
- C'è una nuova colonna da iniziare?
- E c'è una colonna da terminare?
L'ultima domanda è piuttosto interessante per l'output HTML poiché probabilmente vorrai racchiudere non solo gli elementi ma anche la colonna con elementi html.
Fortunatamente con il codice, possiamo impostare tutte queste cose in variabili e creare codice che si adatti sempre alle nostre esigenze.
A volte, non possiamo nemmeno rispondere a ogni domanda dall'inizio. Ad esempio, il conteggio totale degli elementi: ce ne sono, alcuni, multipli, un numero esatto che corrisponde a un numero intero di colonne in totale?
Anche la risposta di Jan Fabry potrebbe funzionare in alcuni casi (come il mio esempio sopra per lo scenario di un elemento per colonna), potresti essere interessato a qualcosa che funzioni per qualsiasi numero di elementi restituiti da WP_Query.
Prima per la matematica:
//
// esempio aritmetico:
//
# configurazione:
$colSize = 20; // numero di elementi in una colonna
$itemsTotal = 50; // numero di elementi (totale)
# calcolo:
$count = 0; // un contatore a base zero
$isStartOfNewColum = 0 === ($count % $colSize); // operazione modulo
$isEndOfColumn = ($count && $isStartOfNewColum) || $count === $itemsTotal; // incapsulamento
Questo codice non viene eseguito, quindi trasformiamolo in un semplice esempio di testo
//
// esempio semplice-text:
//
$column = 0; // inizializza un contatore di colonna
for($count=0; $count<= $itemsTotal; $count++) {
$isStartOfNewColum = 0 === ($count % $colSize); // modulo
$isEndOfColumn = ($count && $isStartOfNewColum);
$isStartOfNewColum && $column++; // aggiorna contatore colonna
if ($isEndOfColumn) {
printf("/Fine della Colonna: %d\n", $column-1);
}
if ($isStartOfNewColum) {
printf("<inizio della Colonna: %d\n", $column);
}
printf(" * elemento %d\n", $count);
}
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
printf("/Fine della Colonna: %d\n", $column);
}
printf("Fatto. Numero totale di Colonne: %d.\n", $column);
Questo in realtà viene eseguito e produce già un output:
<inizio della Colonna: 1
* elemento 0
* elemento 1
* elemento 2
* elemento 3
...
* elemento 17
* elemento 18
* elemento 19
/Fine della Colonna: 1
<inizio della Colonna: 2
* elemento 20
* elemento 21
* elemento 22
...
* elemento 37
* elemento 38
* elemento 39
/Fine della Colonna: 2
<inizio della Colonna: 3
* elemento 40
* elemento 41
* elemento 42
...
* elemento 48
* elemento 49
* elemento 50
/Fine della Colonna: 3
Fatto. Numero totale di Colonne: 3.
Questo simula già abbastanza bene come potrebbe apparire in un template di WordPress:
//
// esempio wordpress:
//
$count = 0; // inizializza contatore elementi
$column = 0; // inizializza contatore colonna
$colSize = 10; // dimensione colonna di dieci questa volta
$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
# variabili di visualizzazione colonne
$isStartOfNewColum = 0 === ($count % $colSize); // modulo
$isEndOfColumn = ($count && $isStartOfNewColum);
$isStartOfNewColum && $column++; // aggiorna contatore colonna
if ($isEndOfColumn) {
print('</ul>');
}
if ($isStartOfNewColum) {
printf('<ul class="col-%d">', $column);
}
?>
<li> ... fai la tua giornata ...
</li>
<?php endwhile; ?>
<?php
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
print('</ul>');
}
// Non devi farlo in ogni loop, basta una volta alla fine
wp_reset_query();
?>
(Non ho eseguito l'ultimo esempio in un ambiente WP, ma dovrebbe essere almeno sintatticamente corretto.)

Questa è più una domanda generale di programmazione, ma ecco l'idea di base:
<?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
// Non è necessario farlo in ogni ciclo, basta una volta alla fine
wp_reset_query();
?>

L'operazione modulo è fondamentalmente la risposta matematica. Ma il tuo esempio manca di un output HTML semantico. Ho proposto qualcosa di simile nella mia risposta, come puoi immaginare ci è voluto un po' più di tempo ;)

wp_reset_query();
non è correlato alla variabile $the_query. Non è affatto necessario, giusto?

@hakre: $the_query->the_post()
sovrascriverà la variabile globale $post
, e wp_reset_query()
la ripristina (chiamando wp_reset_postdata()
- che potrebbe anche essere sufficiente da solo?).

Ok, ho in qualche modo confuso wp_query e post, pensavo che avrebbe fatto qualcosa a $wp_query
ma nell'esempio è stato usato $the_query
. Tuttavia, mi sbagliavo, lo aggiungerò alla mia seconda risposta per completezza.

Non è necessario creare una variabile separata per il conteggio, poiché la query var lo conta già in: $wp_query->current_post
. Inoltre, è necessario considerare l'ultimo elemento della lista per evitare di avere un <ul></ul>
vuoto nel tuo markup.
<?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 che il post è già conteggiato nella variabile $the_query->current_post quando si è nel loop. Aggiungi uno per convertire il conteggio da array a numeri reali.
// L'esempio di Jan non teneva conto dell'ultimo elemento della lista. Non vogliamo avere <ul> vuoti in giro
if ((($the_query->current_post+1) % 10 == 0) && ($the_query->current_post+1 !== count($the_query->posts))):
echo "</ul><ul>";
endif;
endwhile;
echo "</ul>";
?>

Ottimo, mi piace l'aggiunta perché ora il ´<ul></ul>` vuoto è solo per 0 post (ma per quelli rimane) - ma da quello che ho imparato oggi, questa forma è la più piccola senza introdurre una nuova funzione.

Bel miglioramento. Vedo che WP_Query
ha anche una variabile $post_count
, puoi usare quella invece di count($the_query->posts)
. Zac, puoi "annullare l'accettazione" della mia risposta e accettarne un'altra se ha risolto meglio il tuo problema.

Aggiungi la funzione get_columns_array()
al tuo file function.php. Potrai quindi iterare facilmente sulle tue colonne:
Nel tuo tema puoi poi utilizzare un ciclo foreach sulle colonne:
<?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(); ?>
Ho impostato la dimensione predefinita di una colonna a 10. Puoi utilizzare il secondo parametro per impostare la dimensione di una colonna a tuo piacimento. Ad esempio a 7: get_columns_array($post_count, 7);
.

Ecco un altro approccio che puoi utilizzare:
$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="Permalink 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; ?>
