Как разделить цикл на несколько колонок

14 февр. 2011 г., 13:58:16
Просмотры: 31.3K
Голосов: 11

Если у меня есть цикл, работающий с запросом категории, например:

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

Как создать условие, которое разрывает список через определенный интервал и начинает новый? Например, на 10-м посте закрыть </ul> и начать новый <ul> на 11-м.

Это неправильный код, но он иллюстрирует мою цель:

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

Какой правильный способ включить эту логику в цикл?

1
Комментарии

Я обновил свой ответ, добавив решение, которое должно быть простым в использовании и протестировано.

hakre hakre
14 февр. 2011 г. 18:13:41
Все ответы на вопрос 5
0
22

Создание колонок для вашего запроса и удобного отображения

В темах WordPress, вероятно, более полезно иметь что-то, что хорошо вписывается в теговые шаблоны и циклы. Мой первый ответ не уделял этому достаточного внимания. Кроме того, я подумал, что он немного слишком сложен для быстрого внедрения.

Более простой подход, который пришел мне в голову, заключался в расширении "цикла" колонками, и я пришел к следующему решению:

Объект WP_Query_Columns "расширяет" любой стандартный запрос WP колонками, по которым можно легко итерироваться. Первый параметр — это переменная запроса, а второй — количество элементов для отображения в каждой колонке:

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

Чтобы использовать это, просто добавьте класс WP_Query_Columns из этого gist в файл function.php вашей темы.

Продвинутое использование

Если вам нужен номер колонки, которую вы сейчас выводите (например, для некоторых CSS-классов even/odd), вы также можете получить его из foreach:

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

И общее количество колонок также доступно:

<?php 
    $the_columns = new WP_Query_Columns($the_query, 10);
    foreach($the_columns as $column => $column_count) : 
?>
    <h2>Колонка <?php echo $column; ?>/<?php echo sizeof($the_columns); ?></h2>
    <ul>...

Пример для Twenty Ten

Я быстро адаптировал тему Twenty Ten для теста и добавил заголовки над любым циклом таким образом. Код вставлен в loop.php, начало — это код темы:

<?php /* Если нет постов для отображения, например, на пустой странице архива */ ?>
<?php if ( ! have_posts() ) : ?>
    <div id="post-0" class="post error404 not-found">
        <h1 class="entry-title"><?php _e( 'Не найдено', 'twentyten' ); ?></h1>
        <div class="entry-content">
            <p><?php _e( 'Извините, но по вашему запросу ничего не найдено. Возможно, поиск поможет найти связанную запись.', 'twentyten' ); ?></p>
            <?php get_search_form(); ?>
        </div><!-- .entry-content -->
    </div><!-- #post-0 -->
<?php endif; ?>

<!-- WP_Query_Columns -->
<?php 
    ### Требуется WP_Query_Columns --- см. http://wordpress.stackexchange.com/q/9308/178
    $query_copy = clone $wp_query; // сохраняем, чтобы восстановить позже
    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__( 'Постоянная ссылка на %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
    /* Начало цикла.
    ...

Для более подробного ответа:

(это, по сути, как я пришел к вышеизложенному, но лучше объясняет, как фактически решить проблему с помощью простых математических операций. Мое новое решение — итерировать по предварительно вычисленным данным.)

Это зависит от того, насколько вам действительно нужно решить проблему.

Например, если количество элементов на одну колонку равно одному, это очень просто:

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

Даже с этим простым кодом видно, что нужно принять несколько решений:

  • Сколько элементов в одной колонке?
  • Сколько всего элементов?
  • Нужно ли начинать новую колонку?
  • И нужно ли закрывать колонку?

Последний вопрос довольно интересен для HTML-вывода, так как вы, вероятно, хотите заключать не только элементы, но и колонку в HTML-элементы.

К счастью, с помощью кода мы можем установить все это в переменные и создать код, который всегда соответствует нашим потребностям.

А иногда мы даже не можем ответить на все вопросы с самого начала. Например, общее количество элементов: есть ли они, несколько, точное количество, которое соответствует целому числу колонок в общей сложности?

Даже ответ Яна Фабри может работать в некоторых случаях (как мой пример выше для сценария с одним элементом на колонку), вам может быть интересно что-то, что работает для любого количества элементов, возвращаемых WP_Query.

Сначала математика:

//
// арифметический пример:
//
# конфигурация:
$colSize = 20;  // количество элементов в колонке
$itemsTotal = 50; // общее количество элементов

# вычисления:
$count = 0; // счетчик с нулевой базой
$isStartOfNewColum = 0 === ($count % $colSize); // операция modulo
$isEndOfColumn = ($count && $isStartOfNewColum) || $count === $itemsTotal; // инкапсуляция

Этот код не выполняется, поэтому давайте преобразуем его в простой текстовый пример:

//
// простой текстовый пример:
//
$column = 0; // инициализация счетчика колонок
for($count=0; $count<= $itemsTotal; $count++) {
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // обновление счетчика колонок

    if ($isEndOfColumn) {
        printf("/Конец колонки: %d\n", $column-1);
    }

    if ($isStartOfNewColum) {
        printf("<начало колонки: %d\n", $column);
    }

    printf(" * элемент %d\n", $count);
}
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    printf("/Конец колонки: %d\n", $column);
}

printf("Готово. Общее количество колонок: %d.\n", $column);

Это уже выполняется и выводит результат:

<начало колонки: 1
 * элемент 0
 * элемент 1
 * элемент 2
 * элемент 3
...
 * элемент 17
 * элемент 18
 * элемент 19
/Конец колонки: 1
<начало колонки: 2
 * элемент 20
 * элемент 21
 * элемент 22
...
 * элемент 37
 * элемент 38
 * элемент 39
/Конец колонки: 2
<начало колонки: 3
 * элемент 40
 * элемент 41
 * элемент 42
...
 * элемент 48
 * элемент 49
 * элемент 50
/Конец колонки: 3
Готово. Общее количество колонок: 3.

Это уже довольно хорошо имитирует то, как это может выглядеть в шаблоне WordPress:

//
// пример для WordPress:
//
$count = 0; // инициализация счетчика элементов
$column = 0; // инициализация счетчика колонок
$colSize = 10; // размер колонки — десять на этот раз
$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
    # переменные для отображения колонок 
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // обновление счетчика колонок

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

    if ($isStartOfNewColum) {
        printf('<ul class="col-%d">', $column);
    }
?>
    <li> ... сделайте ваш день ...
    </li>
<?php endwhile; ?>
<?php
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    print('</ul>');
}
// Вам не нужно делать это в каждом цикле, достаточно один раз в конце
wp_reset_query();
?>

(Я не выполнял последний пример в среде WP, но он должен быть, по крайней мере, синтаксически правильным.)

14 февр. 2011 г. 15:03:48
5

Это скорее общий вопрос по программированию, но вот основная идея:

<?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
// Не обязательно делать это в каждом цикле, достаточно один раз в конце
wp_reset_query();
?>
14 февр. 2011 г. 14:06:15
Комментарии

Операция modulo - это, по сути, математический ответ. Но вашему примеру не хватает семантического HTML-вывода. Я предложил нечто подобное в своем ответе, и, как вы можете догадаться, это заняло немного больше времени ;)

hakre hakre
14 февр. 2011 г. 15:12:40

wp_reset_query(); не связана с переменной $the_query. Это вообще не нужно, верно?

hakre hakre
14 февр. 2011 г. 17:26:21

@hakre: $the_query->the_post() перезапишет глобальную переменную $post, а wp_reset_query() восстанавливает ее (путем вызова wp_reset_postdata() - что, возможно, само по себе было бы достаточно?).

Jan Fabry Jan Fabry
14 февр. 2011 г. 20:11:27

Хорошо, я немного перепутал wp_query и post, думал, что это как-то повлияет на $wp_query, но в примере использовался $the_query. Однако я ошибся, я добавлю это во второй ответ для полноты картины.

hakre hakre
14 февр. 2011 г. 20:21:24

Вы не учитываете последний элемент. Если цикл заканчивается на числе, кратном 10, вы получите пустой набор <ul></ul>.

Dan Gayle Dan Gayle
15 февр. 2011 г. 02:08:59
4

Нет необходимости создавать отдельную переменную для подсчета, так как переменная запроса уже учитывает это в: $wp_query->current_post. Также нужно учитывать последнюю запись в списке, чтобы избежать пустых <ul></ul> в разметке.

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

    // Обратите внимание, что запись уже учтена в переменной $the_query->current_post внутри цикла. Добавляем единицу для перевода нумерации массива в реальные числа.
    // Пример Яна не учитывал последнюю запись в списке. Не нужно оставлять пустые <ul> в разметке
    if ((($the_query->current_post+1) % 10 == 0) && ($the_query->current_post+1 !== count($the_query->posts))):
        echo "</ul><ul>";
    endif;
endwhile;
echo "</ul>";
?>
14 февр. 2011 г. 21:41:31
Комментарии

Заметил. Пример добавлен.

Dan Gayle Dan Gayle
15 февр. 2011 г. 01:54:42

Отлично, мне нравится это дополнение, потому что пустой ´<ul></ul>` теперь только для 0 постов (но для них он остаётся) - но из того, что я узнал сегодня, эта форма самая компактная без введения новой функции.

hakre hakre
15 февр. 2011 г. 02:50:52

Хорошее дополнение. Я вижу, что WP_Query также имеет переменную $post_count, вы можете использовать её вместо count($the_query->posts). Зак, вы можете "отозвать" мой ответ и принять другой, если он лучше решил вашу проблему.

Jan Fabry Jan Fabry
15 февр. 2011 г. 13:25:15

@Jan - Я бы предпочел инкапсулированную переменную вместо глобальной, так как это повышает модульность. Но хорошо знать, что такая возможность есть.

hakre hakre
16 февр. 2011 г. 10:27:42
0

Добавьте функцию get_columns_array() в ваш файл function.php. Затем вы сможете легко перебирать ваши колонки:

В вашей теме вы можете использовать цикл foreach для перебора колонок:

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

Я установил размер колонки по умолчанию равным 10. Вы можете использовать второй параметр, чтобы задать свой размер колонки. Например, 7: get_columns_array($post_count, 7);.

14 февр. 2011 г. 20:15:05
0

Вот ещё один подход, который можно использовать:

$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="Постоянная ссылка на <?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; ?>
11 сент. 2012 г. 20:33:52