How to show a single post on the front page but have normal paging?

I would like to have a single post on my front page (always the latest), but let normal paging work. So the front page has post 1, the next page should have post 2-11 (1-10 is fine too), then 12-21 or 11-20, and so on. I know I can change the number of posts depending on the context, but setting this to “1” on the homepage means the further pages also show only one post.

My main problem is that /page/2/ and so on works, but /page/1/ always redirects to the real home page, /. This means posts 2-10 are always skipped, since page 2 shows 11-20. I currently solve this by linking to my archive, but this is not ideal when you come to the first posts of the year and there are fewer posts and no obvious way of continuing.

Related posts

Leave a Reply

4 comments

  1. I solved it using the offset query parameter. This allowed me to edit the query in the pre_get_posts hook, and seems to be the cleanest way to do this, without a new query. Now the home page shows only one post, and page/2/ shows posts 2-11. All links keep working, no other modification is required.

    add_action('pre_get_posts', 'set_offset_on_front_page');
    function _set_offset_on_front_page(&$query)
    {
        if (is_front_page() && is_paged()) {
                $posts_per_page = isset($query->query_vars['posts_per_page']) ? $query->query_vars['posts_per_page'] : get_option('posts_per_page');
                // If you want to use 'offset', set it to something that passes empty()
                // 0 will not work, but adding 0.1 does (it gets normalized via absint())
                // I use + 1, so it ignores the first post that is already on the front page
                $query->query_vars['offset'] = (($query->query_vars['paged'] - 2) * $posts_per_page) + 1;
        }
    }
    
  2. Ok, maybe this is a strange or complicated way to do this, but I had a similar problem (I wanted to display a welcome text and the three newest posts of a specific category on the front page. So I did:

    1. Created a new page called home and put my welcome text on it.
    2. Deactivated the default home page and set my custom home page as the start page
    3. Created a new (copied and modified an existing) page template
      1. let it display the page body
      2. load three newest posts of category X and display them
      3. have a link “more” beneath it that links on /category/category-x/

    looks like this: http://hinek.de (page is in german, sorry)

    If this could be the way for you and you need more infos or a code sample for the page template, comment and I will edit this post.

  3. I’m assuming you’re running WordPress 3.0.x?

    To show only one post (in whichever category) on the front page is easy. Use query_posts('post_per_page=1') in your home.php file instead of invoking get_template_part('loop').

    To follow the normal paging methods after that is a little tricky. In your loop.php file, I suggest putting <?php global $paged; ?> before the <?php if (have_posts()) : ?> statement, and using the $paged variable and query_posts() function to modify your query so it shows the right posts.

    Your loop.php file would look something like this (note: not tested):

    <?php
    global $paged;
    
    if (!is_front_page() && $paged && $post->post_type == 'post') :
        query_posts('posts_per_page=10&paged=' . ($paged - 1));
        if (have_posts()) :
            while (have_posts()) : the_post();
            // Rest of the loop
            endwhile;
        endif;
    endif;
    ?>
    

    I used $paged - 1 simply because page 2 will show posts 1 – 10, and page 3 will show posts 11 – 20, and so on.

  4. This question is a bit old, but for those finding this in the modern era, you should never call query_posts. From the WordPress codex:

    query_posts() is overly simplistic and problematic way to modify main
    query of a page by replacing it with new instance of the query. It is
    inefficient (re-runs SQL queries) and will outright fail in some
    circumstances (especially often when dealing with posts pagination).

    TL;DR don’t use query_posts() ever;

    Instead, you should use the pre_get_posts hook in functions.php as follows:

    function hwl_home_pagesize( $query ) {
        // Behave normally for secondary queries
        if ( is_admin() || ! $query->is_main_query() )
            return;
    
        if ( is_home() ) {
            // Display only 1 post for the home page
            $query->set( 'posts_per_page', 1 );
            return;
        }
    
        // Otherwise, use whatever is set in the WordPress Admin screen
        $query->set( 'posts_per_page', get_option('posts_per_page'); );
    }
    add_action( 'pre_get_posts', 'hwl_home_pagesize', 1 );
    

    However, beware that in some cases, (such as adjusting post offsets), using a pre_get_posts hook can mangle your pagination. Fixing this isn’t super-hard, but it’s something to be aware of. There’s an example of how to fix this here.