Получить все записи, включая прикрепленные, с помощью get_posts(), setup_postdata() и цикла foreach?

Вопрос или проблема

Я использую этот код для получения своих постов:

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

Пояснения к коду

  1. Получение параметров страницы:

    • Мы проверяем наличие параметров paged или page и устанавливаем соответствующее значение, чтобы поддерживать пагинацию.
  2. Параметры запроса:

    • Мы создаем массив $query_args, в который включаем тип постов (post), количество постов на странице, текущую страницу и устанавливаем ignore_sticky_posts в false, чтобы липкие посты отображались в самом верхнем порядке.
  3. Цикл запроса:

    • Используем have_posts() и the_post() для итерации по постам и их вывода. Липкие посты будут выводиться первыми благодаря поведению WordPress.
  4. Пагинация:

    • Применяется стандартная функция the_posts_pagination() для навигации по страницам.
  5. Сброс данных:

    • Не забываем сбрасывать данные после выполнения запроса с помощью wp_reset_postdata(), что предотвратит возможные конфликты с последующими запросами.

Заключение

Таким образом, использование WP_Query — это "правильный" и более эффективный подход, чем применение двух последовательных вызовов get_posts() и последующее объединение их массивов. Подход с WP_Query обеспечивает правильную структуру данных и учитывает все особенности работы с липкими постами.

Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой вашего WordPress проекта, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...