Количество прикрепленных сообщений превышает количество сообщений на странице

21

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

function lifelounge_query_adjust( $query ) {
    if ( is_home() ) {
        set_query_var( 'posts_per_page', 12 );
        return;
    }
}
add_filter( 'pre_get_posts', 'lifelounge_query_adjust' );

Но я сталкиваюсь с проблемой с липкими сообщениями. По сути, если у меня есть какие-либо липкие посты, запрос отобразит больше, чем 12 постов, которые я указал, потому что он отобразит 12 плюс любые липкие посты. Я мог бы, конечно, игнорировать липкие посты:

function lifelounge_query_adjust( $query ) {
    if ( is_home() ) {
        set_query_var( 'posts_per_page', 1 );
        set_query_var( 'ignore_sticky_posts', 1 );
        return;
    }
}
add_filter( 'pre_get_posts', 'lifelounge_query_adjust' );

Но я не думаю, что это идеально. Я думаю, что липкие посты должны быть включены в лимит 12 постов, а не добавлены к лимиту. Это то, что имеет наибольшее значение для меня. Есть ли способ достичь этого? Я сделал ошибку, достойную лица?

В значительной степени дубликат: Sticky Posts & Posts Per Page, но это было странно закрыто, поскольку слишком локализовано. Я не согласен, очевидно, потому что я ищу ответ, но также потому, что это вопрос того, почему WordPress не соблюдает posts_per_page ограничения, если вы используете липкие посты. Если вам нужно 12 постов на страницу, вы должны получить 12, а не 13, что вы бы получили, если бы у вас было одно липкое сообщение.

helgatheviking
источник

Ответы:

12

Вот подход для учета липких постов путем получения количества липких постов (если есть) и включения их в posts_per_pageпараметр расчета :

add_action('pre_get_posts', 'ad_custom_query');
function ad_custom_query($query) {

    if ($query->is_main_query() && is_home()) {

        // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {

            // counnt the number of sticky posts
            $sticky_count = count($sticky_posts);

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
                $query->set('posts_per_page', $posts_per_page - $sticky_count);

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set('posts_per_page', 1);
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    }
}

редактировать

В случае, когда количество постов на странице, которое мы хотим установить, меньше или равно количеству прикрепленных постов, я установил posts_per_pageодин, и это приведет к 13 или более постам $sticky_count + 1(в данном случае) только в первом страница (последующие страницы будут иметь 12 сообщений). Может быть, это нормально, так как этот случай редок и +1 пост на первой странице может быть не таким значительным.

Это связано с тем, что Wordpress будет отображать все прикрепленные записи в первую очередь и на одной странице (первой странице), даже если их количество больше, чем posts_per_pageпараметр, поэтому posts_per_pageв этом случае мы устанавливаем минимально возможное количество 1, поскольку 0отрицательные значения отключаются. posts_per_pageпараметр и что будет делать Wordpress , чтобы отобразить все сообщения на первой странице.

Ахмад М
источник
Большой!! Я думаю, что вам нужно перейти $sticky_count + (12 - $sticky_count)на 12- $sticky_countхотя. Например, если у меня есть 1 стикер, то ваша математика все равно сработает до 12, а затем WP добавит стикер, чтобы сделать 13. О, и если if ($sticky_count > $posts_per_page)мы установим значение 12, не будет ли это означать, что мы покажем 24+?
Helgatheviking
@helgatheviking: ты прав. Я всегда делаю такие глупые ошибки, вычисления никогда не были такими интересными для меня. И да, это привело бы к 24 сообщениям. Я обновил код, чтобы учесть это, и добавил проверку для номера страницы. Это работает нормально, но теперь будет один случай, когда $posts_per_pageбудет равен $sticky_count, и здесь я установил параметр posts_per_page равным 1, и я думаю, что все будет в порядке, так как этот случай может быть редким, и это будет только на первой странице ( $sticky_count + 1).
Ахмад М
Спасибо за редактирование! Я думаю, что это лучшее решение, которое мы можем получить, используя липкие посты. Я думаю, что я мог бы в конечном итоге отсортировать по простому мета-ключу для того, чтобы показать сообщение или нет. Это ведет себя более нормально для моего понимания.
Helgatheviking
это не помогает, если липкие сообщения являются частью изначально разыскиваемой posts_per_page. Общее количество постов уменьшится, но прикрепленные посты не будут увеличивать это число, поскольку они являются частью обычного упорядоченного набора дат.
Эндрю Киллен
3

Там проблема, если липкие сообщения находятся на первой странице.

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

function fix_posts_per_page_with_sticky_posts( $query ) {

    if ( $query->is_main_query() ) {

        // set the number of posts per page
        $posts_per_page = 12;

        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );

        // get queried post ids array
        $ids = array();
        $args = array(
            'post_type' => 'post',
            'post_per_page' => $posts_per_page,
            'paged' => 1
        );

        $posts = get_posts( $args );

        foreach ( $posts as $post ) {
            $ids[] = $post->ID;
        }

        // if we have any sticky posts and we are at the first page
        if ( is_array( $sticky_posts ) && ! $query->is_paged() ) {

            // count the number of sticky posts
            $sticky_count = count( $sticky_posts );

            foreach ( $sticky_posts as $sticky_post ) {
                if ( in_array( $sticky_post, $ids ) ) {
                    // decrement sticky posts count if the sticky post in on the page
                    $sticky_count--;
                }
            }

            // and if the number of sticky posts is less than
            // the number we want to set:
            if ( $sticky_count < $posts_per_page ) {
                $query->set( 'posts_per_page', $posts_per_page - $sticky_count );

            // if the number of sticky posts is greater than or equal
            // the number of pages we want to set:
            } else {
                $query->set( 'posts_per_page', 1 );
            }

        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set( 'posts_per_page', $posts_per_page );
        }
    }
}
add_action( 'pre_get_posts', 'fix_posts_per_page_with_sticky_posts'  );

Надеюсь, это поможет

csag
источник
1
Вы уверены, что нет более простого и быстрого решения? Подсказка: вы знаете количество липких постов и постов на странице ...
kaiser
До сих пор я не нашел лучшего .. Это больше исправление для того, что должно быть в ядре WP, по моему мнению
csag
Если бы это было в основном, другие сценарии не сработали бы.
Кайзер
Это известная ошибка, отслеживаемая по адресу core.trac.wordpress.org/ticket/27282
Will.
Решение @kaiser Ahmad M не учитывает липкие посты, которые появлялись бы на первой странице независимо от их липкого состояния. Это может привести к тому, что на первой странице появится слишком мало сообщений (WordPress v4.9.7). Этот ответ лучше, потому что он объясняет это.
Джейкоб Будин
0

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

function modify_main_query( $query ) {
   if ( ( $query->is_home() || is_front_page() ) && $query->is_main_query() ) {
         // set the number of posts per page
        $posts_per_page = 12;
        // get sticky posts array
        $sticky_posts = get_option( 'sticky_posts' );
        // if we have any sticky posts and we are at the first page
        if (is_array($sticky_posts) && !$query->is_paged()) {
            // make a second query to make sure the sticky posts will still work 
            // correctly when on the first page
            // Only reply with the ID's as that is all that is needed
            $args = [
                'post_type' => 'post',
                'post_per_page' => $posts_per_page,
                'paged' => 1,
                'fields' => 'ids'
            ];
            // Array flip to reduce the time taken by 
            // using isset and not in_array
            $posts = array_flip( get_posts( $args ) );

            // count the number of sticky posts
            $sticky_count = count($sticky_posts);

            // loop the posts from the 2nd query to see if the ID's of the sticky posts
            // sit inside it.
            foreach ( $sticky_posts as $sticky_post ) {
                if(isset($posts[$sticky_post])){
                    $sticky_count--;
                }
            }
            // and if the number of sticky posts is less than
            // the number we want to set:
            if ($sticky_count < $posts_per_page) {
               $query->set('posts_per_page', $posts_per_page - $sticky_count);
            } else {
                // if the number of sticky posts is greater than or equal
                // the number of pages we want to set:
                $query->set('posts_per_page', 1);
            }
        // fallback in case we have no sticky posts
        // and we are not on the first page
        } else {
            $query->set('posts_per_page', $posts_per_page);
        }
    } 
}

add_action( "pre_get_posts", 'modify_main_query' );
Эндрю Киллен
источник