Как создать блогролл с постами, отсортированными по категориям и подкатегориям?
Я бы хотел получить помощь в выводе всех записей моего сайта в виде блогролла, отсортированного по категориям и подкатегориям.
Желаемый HTML-результат, который я хочу видеть, должен выглядеть примерно так:
<div id="content">
<div id="category1">
<ul id="posts">
<li>post1</li>
<li>post2</li>
<li>post3</li>
</ul><!-- #posts -->
</div><!-- #category1 -->
<div id="category2">
<div id="sub-category1">
<ul id="posts">
<li>post4</li>
<li>post5</li>
<li>post6</li>
</ul><!-- #posts -->
</div><!-- #sub-category1 -->
<div id="sub-category2">
<ul id="posts">
<li>post7</li>
<li>post8</li>
<li>post9</li>
</ul><!-- #posts -->
</div><!-- #sub-category2 -->
</div><!-- #category2 -->
</div><!-- #content -->
Структура файлов, которую я предполагаю использовать, будет выглядеть примерно так:
custom-category.php
// этот файл будет извлекать категории, сортировать их и создавать контейнеры div для #category и #sub-category, вызывая информацию о постах из своего цикла/запроса с помощью get_template_part( 'content', get_post_format() );
content.php
// этот файл будет сортировать ul#posts и всю информацию, которую я могу добавить относительно самого поста
Сейчас основные проблемы, с которыми я столкнулся, заключаются в том, что я даже не знаю, с чего начать поиск, чтобы попытаться разобраться в этом самостоятельно. Я продолжаю смотреть на файл по умолчанию category.php
, и мне кажется, что мой вариант будет выглядеть совсем не так.
Я пробовал искать плагины, но некоторые только сортируют категории в боковых панелях, другие позволяют создавать пользовательские поля для категорий, но в отзывах упоминается, что нельзя вызывать эти значения. Я пробовал функцию wp_list_categories(); чтобы попытаться начать с чего-то, но она даже не выводит подкатегории.
Я читал о создании собственных query_posts();
или get_posts();
, но я действительно не знаю, с чего начать с ними.
Поскольку это не совсем один вопрос, я хотел бы попытаться выделить вопросы для ясности, но не стесняйтесь добавлять другую информацию, которая, по вашему мнению, может решить проблему, потому что я могу задать неправильные вопросы xD
1- Как начать "Цикл" для получения категорий/подкатегорий?
2- Как отсортировать категории и сохранить вложенность подкатегорий?
3- Как я могу убедиться, что посты попадут в нужные div'ы? На всякий случай, если WP сделает что-то странное.
Спасибо за помощь.
--- Обновление ---
Я искал решения в интернете и начинаю продвигаться вперед, но пока не совсем там. Вот что у меня есть на данный момент:
<?php
// получаем все категории из базы данных
$args1 = array(
'orderby' => 'ID',
'order' => 'ASC',
'hierarchical' => true,
);
$cats = get_categories( $args1 );
// перебираем категории
foreach ($cats as $cat) {
// получаем ID категории
$cat_id= $cat->term_id;
// Создаем заголовок для категории
echo "<h2>".$cat->name."</h2><p>".$cat->term_id."</p>";
// создаем пользовательский запрос WordPress
$args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
query_posts( $args2 );
// запускаем цикл WordPress!
if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php // создаем нашу ссылку теперь, когда пост настроен ?>
<a href="<?php the_permalink();?>"><?php the_title(); ?></a>
<?php echo '<hr/>'; ?>
<?php endwhile; endif; // завершаем наш цикл WordPress. Он начнется снова для каждой категории ?>
<?php } // завершаем оператор foreach ?>
Я нашел этот фрагмент кода на этом сайте. Он выводит все категории и размещает посты под ними, но дублирует посты для родительской категории следующим образом:
<h2>Category1</h2><p>2</p>
<a href="http://localhost/wordpress/2013/05/06/test0/">test0</a>
<hr>
<h2>Category2</h2><p>3</p>
<a href="http://localhost/wordpress/2013/05/15/test2/">test2</a>
<hr>
<a href="http://localhost/wordpress/2013/05/14/test1/">test1</a>
<hr>
<h2>Sub-category1</h2><p>4</p>
<a href="http://localhost/wordpress/2013/05/14/test1/">test1</a>
<hr>
<h2>Sub-category2</h2><p>5</p>
<a href="http://localhost/wordpress/2013/05/15/test2/">test2</a>
<hr>
Как видите, посты test1 и test2 отображаются в Category2, а это не совсем то, что я хотел, как описано в первоначальном вопросе (конечный HTML-результат).
Я считаю, что мне нужно добавить условный оператор для проверки, есть ли у текущей категории дочерние элементы, и если они есть, перейти к дочерним категориям, если нет - заполнить ее. Но я все еще пытаюсь понять, как это сделать. Я еще не достиг точки, где я чувствую себя достаточно комфортно, чтобы начать пытаться реализовать div'ы, которые я планирую иметь в конечном HTML-результате, но у меня есть ощущение, что у меня также возникнут проблемы с этим. На данный момент я в основном пытаюсь узнать больше об этом "цикле", пока не получу достойный результат, который позволит мне разобраться во всем этом.
Я знаю об этих 2 ссылках A и B, но я все еще новичок и пока не могу добраться туда, поэтому я в основном работаю с кодом, который, как я вижу, работает, и буду пытаться улучшить его по мере продвижения.
--- Обновление ---
Кажется, это выводит посты в правильном порядке и без повторения для родительских категорий.
<?php
// получаем все категории из базы данных
$args1 = array(
'orderby' => 'ID',
'order' => 'ASC',
'hierarchical' => true
);
$cats = get_categories( $args1 );
// перебираем категории
foreach ($cats as $cat) {
$cat_id= $cat->term_id;// получаем ID категории
$cat_name= $cat->name;// получаем название категории
$parent= $cat->category_parent;// получаем родительскую категорию
$cat_child= get_term_children( $cat_id, 'category' ); // функция, которую я использовал get_category_children(); была устаревшей... исправил это
$has_child=bool; //
if( empty($cat_child)) { $has_child= false; }
else { $has_child= true; }
if ( $parent == 0 && $has_child == true ) { // является родительской И имеет дочерние -> заголовок поста
echo "<h2>".$cat_name."</h2>";
echo '<hr/>'; }
elseif ( $parent == 0 && $has_child == false ) { // является родительской И не имеет дочерних -> цикл постов
echo "<h2>".$cat_name."</h2>";
// создаем пользовательский запрос WordPress
$args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
query_posts( $args2 );
// запускаем цикл WordPress!
if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php the_title(); ?>
<?php echo '<hr/>'; ?>
<?php endwhile; endif; }
else { // является дочерней -> цикл постов
echo "<h2>".$cat_name."</h2>";
// создаем пользовательский запрос WordPress
$args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
query_posts( $args2 );
// запускаем цикл WordPress!
if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php the_title(); ?>
<?php echo '<hr/>'; ?>
<?php endwhile; endif; // завершаем наш цикл WordPress. Он начнется снова для каждой категории ?>
<?php }} // завершаем оператор foreach ?>
Я разделил это на 3 условия: является родительской и имеет дочерние
, является родительской, но не имеет дочерних
и является дочерней
. Функция, которая позволила мне добраться сюда, - это get_term_children();
.
Читая код сейчас, я понимаю, что мог просто проверить, пуст ли $cat_child
непосредственно в основных операторах if/elseif, избегая обхода $has_child
.

Хорошо, после долгих поисков я пришел к коду, который делает именно то, что я хотел. Однако, я не считаю этот код красивым/эффективным/переиспользуемым. Я просто публикую его, поскольку он выполняет ожидаемое. Я был бы признателен за ответ, который укажет мне на "лучшие практики" программирования, чтобы я мог поучиться, поэтому не буду отмечать вопрос как отвеченный примерно неделю, чтобы дождаться более качественного кода.
Вот результат, к которому я пришел:
<?php
$isOdd = true; // флаг для определения id родительского div для CSS
$args1 = array(
'orderby' => 'ID',
'order' => 'ASC',
'hierarchical' => true
);
$cats = get_categories( $args1 ); // получаем все категории из базы данных
// перебираем категории
foreach ($cats as $cat) {
$cat_id= $cat->term_id; // ID категории
$cat_name= $cat->name; // название категории
$parent= $cat->category_parent; // родительская категория
$cat_child= get_term_children( $cat_id, 'category' ); // получаем дочерние категории из таксономии
$has_child=bool; // переменная для проверки наличия дочерних категорий
if( empty($cat_child)) { $has_child= false; }
else { $has_child= true; }
if ( $parent == 0 && $has_child == false ) { // если родительская и без дочерних - выводим записи
echo "<div class=\"parent-wrap\" id=\"". ( $isOdd ? 'odd' : 'even') . "\">";
echo "<h2>".$cat_name."</h2>";
echo "<div class=\"post-wrap\">";
echo "<ul class=\"post-list\">";
echo "<li class=\"back-button\"><</li>";
// создаем кастомный запрос WordPress
$args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
query_posts( $args2 );
// запускаем цикл WordPress
if (have_posts()) : while (have_posts()) : the_post();
get_template_part( 'content', get_post_format() ); // получаем шаблон поста из content.php
endwhile; endif;
echo "<li class=\"front-button\">></li>";
echo "</ul><!-- .post-list -->";
echo "</div><!-- .post-wrap -->";
echo "</div><!-- .parent-wrap -->";
$isOdd = !$isOdd;
}
elseif ( $parent == 0 && $has_child == true ) { // если родительская и есть дочерние - выводим заголовок
echo "<div class=\"parent-wrap\" id=\"". ( $isOdd ? 'odd' : 'even') . "\">";
echo "<h2>".$cat_name."</h2>";
// перебираем категории внутри условия elseif
foreach ($cats as $cat) {
$cat_id_new= $cat->term_id; // новый ID категории
$cat_name_new= $cat->name; // новое название категории
$parent_new= $cat->category_parent; // новый родитель категории
$cat_child_new= get_term_children( $cat_id_new, 'category' ); // получаем новые дочерние категории
$has_child_new=bool; // новая переменная для проверки дочерних категорий
if( empty($cat_child_new)) { $has_child_new= false; }
else { $has_child_new= true; }
if ($parent_new != 0 && $has_child_new == false && cat_is_ancestor_of($cat_id, $cat_id_new) ) { // если дочерняя - выводим записи
echo "<div class=\"child-wrap\">";
echo "<h3>".$cat_name_new."</h3>";
echo "<div class=\"post-wrap\">";
echo "<ul class=\"post-list\">";
echo "<li class=\"back-button\"><</li>";
// создаем кастомный запрос WordPress
$args2 = 'cat=' . $cat_id_new . '&orderby=date&order=DESC&post_per_page=-1';
query_posts( $args2 );
// запускаем цикл WordPress
if (have_posts()) : while (have_posts()) : the_post();
get_template_part( 'content', get_post_format() ); // получаем шаблон поста из content.php
endwhile;
endif; // завершаем цикл WordPress. Он запустится снова для каждой категории
echo "<li class=\"front-button\">></li>";
echo "</ul><!-- .post-list -->";
echo "</div><!-- .post-wrap -->";
echo "</div><!-- .child-wrap -->";
} // закрываем if ($parent_new != 0...
} // закрываем foreach в elseif
echo "</div><!-- .parent-wrap -->";
$isOdd = !$isOdd;
} // закрываем if ($parent == 0...
} // закрываем первый foreach ?>
Мне кажется, что некоторые вещи в этом коде можно было бы лучше организовать, создав функции и затем переиспользуя их по всему коду, и я все еще думаю о замене query_posts();
на get_posts();
или pre_get_posts();
.
