Как получить точное количество записей в стандартном запросе WP?

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

Я пытаюсь изменить стандартный запрос WP, чтобы избежать проблем с пагинацией.
Необходимо получить точное количество постов независимо от максимального количества постов на страницу.

Я хочу иметь возможность выбирать, где и когда показывать только 1, 2 или любое количество постов. Поэтому, если я выберу число больше максимального количества постов на страницу, категория будет разбита на страницы. Таким образом, оба параметра важны: ‘numberposts’ и ‘posts_per_page’.

Но стандартный запрос WP, вызванный через query_posts(), не использует параметр ‘numberposts’ и полностью его игнорирует. И если я установлю параметр ‘posts_per_page’ (вместо ‘numberposts’) на, например, 1, категория просто разделится на множество страниц, каждая с одним постом.

Так как же это достичь? Если это вообще возможно со стандартным запросом…

$category = get_queried_object();
$category_metadata = get_fields('category_'. $category->term_id);

$posts_output = isset($category_metadata['ctgr_posts_out']) ? $category_metadata['ctgr_posts_out'] : false;
$posts_order = isset($category_metadata['ctgr_posts_order']) ? $category_metadata['ctgr_posts_order'] : 'datetolow';
$posts_mode = isset($category_metadata['ctgr_posts_mode']) ? $category_metadata['ctgr_posts_mode'] : 'simple';
$posts_total = isset($category_metadata['ctgr_posts_total']) ? $category_metadata['ctgr_posts_total'] : -1;  // << ЭТО ПРОБЛЕМА, значение, переданное из метаполя, не влияет
$posts_per_page = isset($category_metadata['ctgr_posts_per_page']) ? $category_metadata['ctgr_posts_per_page'] : 20;  // << ЭТО ТОЖЕ ВАЖНО и не должно быть удалено
$posts_date_format = isset($category_metadata['ctgr_posts_date_format']) ? $category_metadata['ctgr_posts_date_format'] : null;

$posts_body = null;
$pagination_body = null;

$query_custom_args = [
    'post_status'       => 'publish',
    'numberposts'       => $posts_total,
    'posts_per_page'    => $posts_per_page,
];
switch($posts_output) {
    case 'own':
        // только собственные посты
        $query_custom_args['category__in'] = $category->term_id;
        break;
    case 'all':
        // собственные и подкатегорийные посты
        $query_custom_args['category'] = $category->term_id;
        break;
    default:
        // значение 'hide'
        $posts_output = false;
}
switch($posts_order) {
    case 'datetolow':
        $query_custom_args['orderby'] = 'date';
        $query_custom_args['order'] = 'DESC';
        break;
    case 'datetohigh':
        $query_custom_args['orderby'] = 'date';
        $query_custom_args['order'] = 'ASC';
        break;
    default:
        // значение 'titletohigh'
        $query_custom_args['orderby'] = 'title';
        $query_custom_args['order'] = 'ASC';
}

global $query_string;
parse_str($query_string, $query_default_args);
$query_args = array_merge($query_default_args, $query_custom_args);
query_posts($query_args);

if($posts_output && have_posts()) {
    // посты
    $posts_body = '<div class="category_posts_'. $posts_mode .' category_posts"><ul class="posts_list">';
    while(have_posts()) {
        the_post();
        $post_alt_title = get_field('post_alt_title', $post);
        $post_title = $post_alt_title ? string_unbreak($post_alt_title) : get_the_title($post);
        $post_link = get_permalink($post);
        $post_image_url = $post_excerpt = $post_date = null;
        $post_image_body = $post_date_body = null;

        if($posts_mode != 'simple') {
            $post_image_url = get_the_post_thumbnail_url($post, 'large') ?: null;
            $post_alt_excerpt = get_field('post_alt_excerpt', $post);
            $post_excerpt = $post_alt_excerpt ?: get_the_excerpt($post);
            $post_date = $posts_date_format ? get_the_date($posts_date_format, $post) : null;
            
            $post_image_body = $post_image_url ? '<img class="post_image" src="'. $post_image_url .'" alt="'. $post_title .'">' : null;
            $post_date_body = $post_date ? '<div class="post_date">'. $post_date .'</div>' : null;
        }
        
        if($posts_mode == 'extended') {
            $posts_body .= '
            <li class="post_extended post_item">
                '. $post_image_body .'
                <div class="post_description">
                    <div class="post_title">
                        <h2><a href="'. $post_link .'">'. $post_title .'</a></h2>
                    </div>
                    <div class="post_text text_content">'. $post_excerpt .'</div>
                    <div class="post_extra">
                        '. $post_date_body .'
                        <a class="post_more" href="'. $post_link .'">Читать далее >>></a>
                    </div>
                </div>
            </li>';
        }
        else {  // значение 'simple'
            $posts_body .= '
            <li class="post_simple post_item">
                <a class="post_link" href="'. $post_link .'">'. $post_title .'</a>
            </li>';
        }
    }
    $posts_body .= '</ul></div>';

    // пагинация
    if($wp_query->max_num_pages > 1) {
        $pagination_body = '
        <div class="category_pagination">'.
            get_the_posts_pagination([
                'show_all'     => false,
                'end_size'     => 3,
                'mid_size'     => 5,
                'prev_next'    => false,
                'prev_text'    => __('Назад'),
                'next_text'    => __('Вперед'),
                'add_args'     => false,
                'add_fragment' => '',
                'screen_reader_text' => __( 'Навигация по постам' ),
            ])
        .'</div>';
    }
}

wp_reset_query();

.

Ответ или решение

Чтобы точно определить количество постов в стандартном запросе WordPress, нужно понимать, какие параметры влияют на формирование результата и как они взаимодействуют. Вопрос задает внимание на конфликте между параметрами numberposts и posts_per_page, и требует подхода, который учитывает пагинацию и гибкость настройки числа постов на странице.

Теория

WordPress предлагает несколько способов запроса постов, и двое из них — query_posts() и get_posts() — часто путаются пользователями. Когда вы используете query_posts(), вы модифицируете главный цикл, управляемый $wp_query, что может вызывать проблемы с пагинацией, как в вашем случае.

Параметр numberposts на самом деле используется в функции get_posts(), но не поддерживается в query_posts() и WP_Query. Вместо него обычно используется posts_per_page, который контролирует число постов, которые отображаются на странице.

Для корректного управления показом постов важно понять, что комбинация параметров posts_per_page и paged (номер текущей страницы) как раз и управляет тем, какие и сколько постов выводятся на данной странице.

Пример

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

  1. Подсчитайте общее количество постов в категории:
$category_id = get_queried_object_id();
$total_posts = new WP_Query([
    'cat' => $category_id,
    'posts_per_page' => -1,
    'fields' => 'ids'
]);
$total_post_count = $total_posts->post_count;

Эта часть кода даст вам точное количество постов в категории. Параметр 'posts_per_page' => -1 извлекает все посты в категории без ограничения по числу.

  1. Теперь используем WP_Query для пагинации и отображения постов:
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = [
    'cat' => $category_id,
    'posts_per_page' => $posts_per_page, // количество постов на одной странице
    'paged' => $paged, // текущая страница
    'order' => 'DESC',
    'orderby' => 'date'
];

$custom_query = new WP_Query($args);

if ($custom_query->have_posts()) : 
    while ($custom_query->have_posts()) : $custom_query->the_post();
        // Ваш вывод поста
    endwhile;

    // Пагинация
    echo paginate_links([
        'total' => $custom_query->max_num_pages
    ]);

endif;
wp_reset_postdata();

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

Применение

Теперь, когда вы понимаете, как использовать WP_Query и параметры, влияющие на количество постов, вы можете динамически настроить ваш код в зависимости от ваших потребностей. Если вы хотите выводить больше постов на странице, контролируйте это изменением значения переменной $posts_per_page. Убедитесь, что функция paginate_links() правильно отображает и навигацию между страницами.

Таким образом, главным партнером в решении проблемы с точным подсчетом и отображением постов является комбинация использования WP_Query с правильно установленными параметрами posts_per_page и paged, что позволит вам управлять не только выводом, но и общей логикой навигации по категориям.

Этот подход обеспечит не просто корректную работу сайта в широком диапазоне сценариев, но и даст гибкость в дальнейшем развитии функциональности, снижая риск потенциальных конфликтов или ошибок, связанных с пагинацией.

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

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