Como dividir um loop em várias colunas

11

Se eu tiver um loop em execução em uma consulta de categoria 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>

Como eu criaria uma cláusula if que quebra a lista em um determinado intervalo e inicia uma nova. Por exemplo, no 10º post, retorne a </ul>e inicie um novo <ul>às 11.

Isso está incorreto, mas para ilustrar meu 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>";
        }

Qual é a maneira correta de incluir essa lógica no loop?

zac
fonte
Atualizei minha resposta com algo que geralmente deve ser fácil de usar e testar.
hakre

Respostas:

21

Crie colunas para sua consulta e exibição fácil

Nos temas é provavelmente mais útil ter algo que se encaixe bem nas tags de modelo e no loop. Minha primeira resposta não se concentrou muito nisso. Além disso, achei um pouco complicado demais para uma adoção rápida.

Uma abordagem mais fácil que me veio à mente foi estender o "loop" com colunas e chegar a esta solução até agora:

Um objeto WP_Query_Columns "estende" qualquer consulta WP padrão com colunas que podem ser facilmente iteradas. O primeiro parâmetro é a variável de consulta e o segundo parâmetro é o número de itens a serem exibidos por coluna:

<?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 usá-lo, basta adicionar a classe WP_Query_Columns desta lista aos seus temas function.php.

Uso Avançado

Se você precisar do número da coluna que está exibindo no momento (por exemplo, para algumas classes CSS pares / ímpares, também é possível obtê-lo no foreach:

<?php foreach(new WP_Query_Columns($the_query, 10) as $column => $column_count) : ?>

E o número total de colunas também está disponível:

<?php 
    $the_columns = new WP_Query_Columns($the_query, 10);
    foreach($the_columns as $column => $column_count) : 
?>
    <h2>Column <?php echo $column; ?>/<?php echo sizeof($the_columns); ?></h2>
    <ul>...

Exemplo de vinte e dez

Eu poderia rapidamente invadir o tema vinte e dez para um teste e adicionar títulos acima de qualquer loop dessa maneira. Ele está inserido no loop.php, o começo é o código do tema:

<?php /* If there are no posts to display, such as an empty archive page */ ?>
<?php if ( ! have_posts() ) : ?>
    <div id="post-0" class="post error404 not-found">
        <h1 class="entry-title"><?php _e( 'Not Found', 'twentyten' ); ?></h1>
        <div class="entry-content">
            <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyten' ); ?></p>
            <?php get_search_form(); ?>
        </div><!-- .entry-content -->
    </div><!-- #post-0 -->
<?php endif; ?>

<!-- WP_Query_Columns -->
<?php 
    ### Needs WP_Query_Columns --- see http://wordpress.stackexchange.com/q/9308/178
    $query_copy = clone $wp_query; // save to restore later
    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 to %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
    /* Start the Loop.
    ...

Para uma resposta mais longa:

(foi basicamente como cheguei ao assunto acima, mas explica melhor como realmente resolver o problema com operações matemáticas simples. Minha nova solução é iterar sobre algo pré-calculado.)

Depende um pouco do quanto você realmente precisa para resolver o problema.

Por exemplo, se o número de itens por coluna for igual a um, isso é muito simples:

<?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>

Mesmo com esse código simples, pode-se ver que há várias decisões a serem tomadas:

  • Quantos itens estão em uma coluna?
  • Quantos itens existem no total?
  • Existe uma nova coluna para começar?
  • E existe uma coluna para terminar?

A última pergunta é bastante interessante para a saída HTML, pois você provavelmente deseja incluir não apenas itens, mas também a coluna com elementos html.

Felizmente, com o código, podemos definir tudo isso em variáveis ​​e criar código que sempre calcula nossas necessidades.

E, às vezes, nem podemos responder a todas as perguntas desde o início. Por exemplo, a contagem do total de itens: existe alguma, múltipla, uma contagem exata que corresponda a um número inteiro de colunas no total?

Mesmo a resposta de Jan Fabry pode funcionar em alguns casos (como meu exemplo acima funciona no cenário de um item por coluna), você pode estar interessado em algo que funcione para qualquer número de itens retornados pelo WP_Query.

Primeiro para a matemática:

//
// arithmetical example:
//
# configuration:
$colSize = 20;  // number of items in a column
$itemsTotal = 50; // number of items (total)

# calculation:
$count = 0; // a zero-based counter variable
$isStartOfNewColum = 0 === ($count % $colSize); // modulo operation
$isEndOfColumn = ($count && $isStartOfNewColum) || $count === $itemsTotal; // encapsulation

Esse código não é executado, então vamos colocar isso em um exemplo de texto simples

//
// simple-text example:
//
$column = 0; // init a column counter
for($count=0; $count<= $itemsTotal; $count++) {
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // update column counter

    if ($isEndOfColumn) {
        printf("/End of Column: %d\n", $column-1);
    }

    if ($isStartOfNewColum) {
        printf("<start of Column: %d\n", $column);
    }

    printf(" * item %d\n", $count);
}
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    printf("/End of Column: %d\n", $column);
}

printf("Done. Total Number of Columns: %d.\n", $column);

Isso realmente é executado e já produz alguma saída:

<start of Column: 1
 * item 0
 * item 1
 * item 2
 * item 3
...
 * item 17
 * item 18
 * item 19
/End of Column: 1
<start of Column: 2
 * item 20
 * item 21
 * item 22
...
 * item 37
 * item 38
 * item 39
/End of Column: 2
<start of Column: 3
 * item 40
 * item 41
 * item 42
...
 * item 48
 * item 49
 * item 50
/End of Column: 3
Done. Total Number of Columns: 3.

Isso já simula muito bem como poderia ser um modelo de wordpress:

//
// wordpress example:
//
$count = 0; // init item counter
$column = 0; // init column counter
$colSize = 10; // column size of ten this time
$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
    # columns display variables 
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // update column counter

    if ($isEndOfColumn) {
        print('</ul>');
    }

    if ($isStartOfNewColum) {
        printf('<ul class="col-%d">', $column);
    }
?>
    <li> ... make your day ...
    </li>
<?php endwhile; ?>
<?php
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    print('</ul>');
}
// You don't have to do this in every loop, just once at the end should be enough
wp_reset_query();
?>

(Não executei o último exemplo em um ambiente WP, mas deve estar pelo menos sintaticamente correto.)

hakre
fonte
2

Esta é mais uma questão de programação geral, mas aqui está a idéia 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
// You don't have to do this in every loop, just once at the end should be enough
wp_reset_query();
?>
Jan Fabry
fonte
A operação do módulo é basicamente a resposta matemática. Mas seu exemplo não possui saída HTML semântica. Eu já propôs algo semelhante em minha resposta, como você pode imaginar, levou mais algum tempo;)
hakre
wp_reset_query();não está relacionado à variável $ the_query. Isso não é necessário, certo?
hakre
@ hakre: $the_query->the_post()substituirá a $postvariável global e a wp_reset_query()restaurará (chamando wp_reset_postdata()- o que também pode ser suficiente por si só?).
Jan Fabry
Ok, de alguma forma misturei wp_query e postei um pouco, pensei que faria algo, $wp_querymas $the_queryfoi usado no exemplo. No entanto, eu estava errado, vou adicioná-lo à minha segunda resposta por completo.
hakre
Você não está contabilizando o último item. Se o loop terminar em um número divisível por 10, você receberá um conjunto vazio de <ul></ul>.
Dan Gayle
1

Não há necessidade de criar uma var separado para contar, como o var consulta já conta ele em: $wp_query->current_post. Além disso, você precisa levar em consideração a entrada final na lista para não ficar vazio <ul></ul>na sua marcação.

<?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>";

    // Note that the post is already counted in the $the_query->current_post variable when in the loop. Add one to translate array counting to real counts.
    // Jan's example didn't account for the final entry in the list. Don't want empty <ul>'s hanging around
    if ((($the_query->current_post+1) % 10 == 0) && ($the_query->current_post+1 !== count($the_query->posts))):
        echo "</ul><ul>";
    endif;
endwhile;
echo "</ul>";
?>
Dan Gayle
fonte
Notado. Exemplo adicionado.
Dan Gayle
Legal, eu gosto da adição porque o vazio ´ <ul> </ul> `é apenas para 0 posts agora (mas para aqueles que ainda são) - mas pelo que eu aprendi hoje, esse formulário é o menor com o introdução de uma nova função.
21711 hakre
Adição agradável. Vejo que WP_Querytambém tem uma $post_countvariável, você pode usar isso em vez de count($the_query->posts). Zac, você pode "inaceitar" minha resposta e aceitar outra, se resolver o seu problema melhor.
Jan Fabry
@ Jan - Eu preferiria a variável encapsulada sobre a global porque isso aumenta a modularidade. Mas é bom saber que existe um.
hakre
0

Adicione a get_columns_array()função ao seu function.php. Você pode iterar facilmente sobre suas colunas:

No seu tema, você foreach cada loop sobre as colunas:

<?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(); ?>

Defino o tamanho padrão de uma coluna como 10. Você pode usar o segundo parâmetro para definir o tamanho de uma coluna por conta própria. Gostaria de 7: get_columns_array($post_count, 7);.

hakre
fonte
0

Aqui está outra abordagem que você pode adotar:

$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 to <?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; ?>
Vincent
fonte