16

I need to have a different amount of posts per page on the first page that on the other pages.

For example, this is what I need

  • Total posts: 6
  • First page: showing 3 posts
  • Following page: showing 2 posts per page

Here's my code:

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

$fp_limit = 3; // first page limit
$limit = 2; // following page limit
$offset = 0; // default offset

if( $paged == 1 ) {
    $limit = $fp_limit;
} else {
    $offset = $fp_limit + ( ($paged - 2) * $limit );
}

$args = array(
    'post_type' => 'my_post_type',
    'post_status' => 'publish',
    'offset' => $offset,
    'posts_per_page' => $limit,
    'caller_ get_ posts' => -1, // remove sticky post
    'paged' => $paged,
    'tax_query' => array(
        array(
            'taxonomy' => 'my_taxo',
            'field' => 'slug',
            'terms' => array('slug1', 'slug2', 'slug3')
        )
    )
);
$my_query = null;
$my_query = new WP_Query($args);

// basic loop
if( $my_query->have_posts() ) : 
while ($my_query->have_posts()) : $my_query->the_post();

...

endwhile; endif; // archive loop
if (function_exists('wp_pagenavi')){ wp_pagenavi( array( 'query' => $my_query ) ); }

wp_reset_query();

At first page in archive, this code assumes:

Well, 6 posts total and 3 posts per page. So I need 2 archive pages and the pagination I present to you is:

[1] [2]

However, any other page in archive the code assumes:

Well, 6 posts total and 2 posts per page. So I need 3 archive pages and the pagination I present to you is:

[1] [2] [3]

Need a little help to fix this.

7
  • If only I could tell WP_pagenavi how many posts at 1st page and the rest...
    – norixxx
    Commented Jul 25, 2014 at 9:59
  • Why exactly do you need to do it this way. Any particular reason Commented Jul 25, 2014 at 10:06
  • Just my client's selfishness. I actually do not care if I use wp_pagenavi or not. Any other technique I can use?
    – norixxx
    Commented Jul 25, 2014 at 10:12
  • 2
    First off 'caller_ get_ posts' contains spaces and is not valid. Second, it's deprecated. Use ignore_sticky_posts instead.
    – kaiser
    Commented Jul 25, 2014 at 12:22
  • Your home page, is it a normal homepage or set as a front page Commented Jul 25, 2014 at 12:48

3 Answers 3

25

EDIT - ANSWER REVISITED

I've being working on another solution which is actually better the original answer. This does not involve any custom query and I think for all purposes my original answer can be dropped but kept for informational purposes

I still believe you are on the homepage and will also treat this as such. So this is my new solution

STEP 1

Remove the custom query from the homepage and replace it with the default loop

<?php

        if ( have_posts() ) :
            // Start the Loop.
            while ( have_posts() ) : the_post();

                ///<---YOUR LOOP--->

            endwhile;

                //<---YOUR PAGINATION--->   

            else : 

                //NO POSTS FOUND OR SOMETHING   

            endif; 

    ?>

STEP 2

Use pre_get_posts to alter the main query to add your custom taxonomy to the main query to display on the home page.

STEP 3

Now, get the posts_per_page option set from the back end (which I assume is 2) and also set your offset which we are going to use. That will be 1 as you will need 3 posts on page one and 2 on the rest

$ppg = get_option('posts_per_page');
$offset = 1;

STEP 4

On page one, you'll need to add the offset to posts_per_page will add up to 3 to get your three posts on page one.

$query->set('posts_per_page', $offset + $ppp);

STEP 5

You must apply your offset to all subsequent pages, otherwise you will get a repetition of the last post of the page on the next page

$offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
$query->set('posts_per_page',$ppp);
$query->set('offset',$offset); 

STEP 6

Lastly, you need to subtract your offset from found_posts otherwise your pagination on the last page will be wrong and give you a 404 error as the last post will be missing due to the incorrect post count

NOTE: This piece of code broke pagination on the search page. This is now fixed, see the updated code

function homepage_offset_pagination( $found_posts, $query ) {
    $offset = 1;

    if( $query->is_home() && $query->is_main_query() ) {
        $found_posts = $found_posts - $offset;
    }
    return $found_posts;
}
add_filter( 'found_posts', 'homepage_offset_pagination', 10, 2 );

ALL TOGETHER

This is how your complete query will look like that should go into functions.php

function tax_and_offset_homepage( $query ) {
  if ($query->is_home() && $query->is_main_query() && !is_admin()) {
    $query->set( 'post_type', 'my_post_type' );
    $query->set( 'post_status', 'publish' );
    $query->set( 'ignore_sticky_posts', '-1' );
    $tax_query = array(
        array(
            'taxonomy' => 'my_taxo',
            'field' => 'slug',
            'terms' => array('slug1', 'slug2', 'slug3')
        )
    );
    $query->set( 'tax_query', $tax_query );
    $ppp = get_option('posts_per_page');
    $offset = 1;
    if (!$query->is_paged()) {
      $query->set('posts_per_page',$offset + $ppp);
    } else {
      $offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
      $query->set('posts_per_page',$ppp);
      $query->set('offset',$offset);
    }
  }
}
add_action('pre_get_posts','tax_and_offset_homepage');

function homepage_offset_pagination( $found_posts, $query ) {
    $offset = 1;

    if( $query->is_home() && $query->is_main_query() ) {
        $found_posts = $found_posts - $offset;
    }
    return $found_posts;
}
add_filter( 'found_posts', 'homepage_offset_pagination', 10, 2 );
1
  • Another way is to avoid using offset and use 'post__not_in' excluding first post from queries in pages !== 0. Commented Dec 4, 2020 at 17:10
4

I know this is from 1000 years ago, but another solution for anyone else looking for this solution while using a custom query, here is how to do it. In this example the 1st page needed 10 posts and every subsequent page needs 9.

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
if( $paged == 1 ) {
   $limit = 10;
} else {
   $limit = 9;
}

and then in the array use this:

'posts_per_page' => $limit,

Now you're good to go.

1
  • 6
    This won't work. With this you will have post #10 be displayed twice. Since when going on the second page it will "think" that the first page also had 9 posts displayed and therefore will start showing post #10 although it already got displayed on the first page.
    – leymannx
    Commented May 9, 2019 at 6:24
2

Kiel was really close. I needed 3 on the front page, 12 on subsequent pages, this is where I landed:

<?php 
$paged = ( get_query_var( 'paged' ) ) ? absint( get_query_var( 'paged' ) ) : 1;
$current_cat = get_category($cat);

$limit = 12; // Set the posts limit on all the pages but the first
$offset = 3; // Set this to the number of posts on the first page

if( $paged == 1 ) {
   $offset = 0; // No offset on the first page
   $limit = 3; // Number of posts on the front
} else {
   $offset = (($paged - 2) * $limit) + $offset; // The magic happens here
}

$args = array(
    'post_type' => 'post',
    'category_name' => $current_cat->slug,
    'paged' => $paged,
    'offset' => $offset,
    'posts_per_page' => $limit,
    'orderby' => 'date',
    'order' => 'DESC',
);
?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.