Вопрос или проблема
Я использую этот код для получения своих постов:
<?php
if ( get_query_var( 'paged' ) ) {
$paged = absint( get_query_var( 'paged' ) );
} elseif ( get_query_var( 'page' ) ) {
$paged = absint( get_query_var( 'page' ) );
} else {
$paged = 1;
}
$default_posts_per_page = get_option( 'posts_per_page' );
$args = array(
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'paged' => $paged,
);
$postslist = get_posts( $args );
$temp = $wp_query;
$wp_query = null;
$wp_query = new WP_Query( $args );
$count = $wp_query->post_count;
?>
<?php foreach( $postslist as $post ) : setup_postdata( $post ); ?>
<div <?php post_class(); ?> id="post-<?php the_ID(); ?>">
<?php get_template_part( 'template-parts/content', 'three-columns' ); ?>
<?php endforeach; ?>
<?php if ( 0 === $count ) {
get_template_part( 'template-parts/content', 'none' );
} ?>
<?php
wp_reset_postdata(); ?>
<?php
$wp_query = null;
$wp_query = $temp;
?>
Этот код получает мои посты без проблем и отображает их, но есть одна маленькая деталь, о которой нужно позаботиться…
Мои закрепленные посты нигде не найдены! (они не отображаются на главной странице).
Итак, мой вопрос: Существует ли «вордпресный» (без хаков) способ получить все посты, включая закрепленные?
В общем, я хочу, чтобы этот код работал как обычный цикл ( закрепленные посты сначала, за ними следуют обычные посты, а затем снова отображается закрепленный пост в их хронологически правильной позиции во времени ).
Чтобы заставить мой код работать как обычный цикл, я использую этот хаковский обход:
<?php
if ( get_query_var( 'paged' ) ) {
$paged = absint( get_query_var( 'paged' ) );
} elseif ( get_query_var( 'page' ) ) {
$paged = absint( get_query_var( 'page' ) );
} else {
$paged = 1;
}
$default_posts_per_page = get_option( 'posts_per_page' );
$args = array(
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'include' => implode(',', get_option('sticky_posts')),
'paged' => $paged,
);
$args2 = array(
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'paged' => $paged,
);
$postslist = get_posts( $args );
$postslist2 = get_posts( $args2 );
$postslist = array_merge( $postslist, $postslist2 );
$postslist = array_map("unserialize", array_unique(array_map("serialize", $postslist)));
$temp = $wp_query;
$wp_query = null;
$wp_query = new WP_Query( $args );
$count = $wp_query->post_count;
?>
<?php foreach( $postslist as $post ) : setup_postdata( $post ); ?>
<div <?php post_class(); ?> id="post-<?php the_ID(); ?>">
<?php get_template_part( 'template-parts/content', 'three-columns' ); ?>
<?php endforeach; ?>
<?php if ( 0 === $count ) {
get_template_part( 'template-parts/content', 'none' );
} ?>
<?php
wp_reset_postdata(); ?>
<?php
$wp_query = null;
$wp_query = $temp;
?>
Этот код теперь работает как обычный цикл, но он кажется хаком, потому что, как вы можете видеть, я использую get_posts()
дважды (определенно избыточно), а затем использую array_merge()
, чтобы объединить два get_posts()
в один array
, и в конце удаляю дублирующиеся посты с помощью array_map()
и array_unique()
.
Итак, я повторю вопрос: Существует ли лучший (вордпресный/без хаков) способ получить все посты, включая закрепленные, с помощью цикла foreach?
Спасибо, ребята!!
Обновленный ответ:
Стандартное поведение WP именно то, что вам нужно. Проблема в том, что вы используете get_posts()
, который полностью игнорирует поведение закрепленных постов, устанавливая ignore_sticky_posts = true
(проверьте исходный код). Поэтому вам нужен только один запрос, просто используйте WP_Query():
$postsList = new WP_Query([
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'paged' => $paged
]);
Закрепленные посты будут вверху, а если их много, они будут повторяться на страницах в порядке их даты (стандартное упорядочивание).
Чтобы избежать «закрепленности» постов, используйте 'ignore_sticky_posts' => true
в своем запросе. Это не исключает закрепленные посты, просто убирает «закрепленное поведение», так что посты будут упорядочены по дате (стандартное упорядочивание).
new WP_Query([
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'paged' => $paged,
'ignore_sticky_posts' => true
]);
Ссылка на Codex: https://codex.wordpress.org/Class_Reference/WP_Query#Pagination_Parameters
Ответ или решение
Чтобы получить все посты в WordPress, включая "липкие" (sticky) посты, наиболее эффективный и стандартный способ — использовать класс WP_Query
. В вашем случае get_posts()
действительно не учитывает поведение липких постов, так как при его использовании по умолчанию устанавливается параметр ignore_sticky_posts
в true
.
Пример решения с использованием WP_Query
Для того чтобы получить все посты, включая липкие, и корректно отобразить их в соответствии с вашими требованиями, используйте следующий код:
<?php
if ( get_query_var( 'paged' ) ) {
$paged = absint( get_query_var( 'paged' ));
} elseif ( get_query_var( 'page' ) ) {
$paged = absint( get_query_var( 'page' ));
} else {
$paged = 1;
}
$default_posts_per_page = get_option( 'posts_per_page' );
$query_args = array(
'post_type' => 'post',
'posts_per_page' => $default_posts_per_page,
'paged' => $paged,
'ignore_sticky_posts' => false, // Устанавливаем в false для получения липких постов
);
$wp_query = new WP_Query($query_args);
?>
<?php if ($wp_query->have_posts()) : ?>
<?php while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
<div <?php post_class(); ?> id="post-<?php the_ID(); ?>">
<?php get_template_part('template-parts/content', 'three-columns'); ?>
</div>
<?php endwhile; ?>
<?php
// Пагинация
the_posts_pagination();
?>
<?php else : ?>
<?php get_template_part('template-parts/content', 'none'); ?>
<?php endif; ?>
<?php
wp_reset_postdata();
?>
Пояснения к коду
-
Получение параметров страницы:
- Мы проверяем наличие параметров
paged
илиpage
и устанавливаем соответствующее значение, чтобы поддерживать пагинацию.
- Мы проверяем наличие параметров
-
Параметры запроса:
- Мы создаем массив
$query_args
, в который включаем тип постов (post
), количество постов на странице, текущую страницу и устанавливаемignore_sticky_posts
вfalse
, чтобы липкие посты отображались в самом верхнем порядке.
- Мы создаем массив
-
Цикл запроса:
- Используем
have_posts()
иthe_post()
для итерации по постам и их вывода. Липкие посты будут выводиться первыми благодаря поведению WordPress.
- Используем
-
Пагинация:
- Применяется стандартная функция
the_posts_pagination()
для навигации по страницам.
- Применяется стандартная функция
-
Сброс данных:
- Не забываем сбрасывать данные после выполнения запроса с помощью
wp_reset_postdata()
, что предотвратит возможные конфликты с последующими запросами.
- Не забываем сбрасывать данные после выполнения запроса с помощью
Заключение
Таким образом, использование WP_Query
— это "правильный" и более эффективный подход, чем применение двух последовательных вызовов get_posts()
и последующее объединение их массивов. Подход с WP_Query
обеспечивает правильную структуру данных и учитывает все особенности работы с липкими постами.
Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой вашего WordPress проекта, не стесняйтесь обращаться!