10

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.

4 Answers 4

9

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;
    }
}
4
  • If this works, then the OP should use this.
    – john010117
    Commented Aug 12, 2010 at 16:54
  • Which I do, because I wrote the question and this answer. But thank you for your suggestions, they brought me on the right track.
    – Jan Fabry
    Commented Aug 12, 2010 at 17:48
  • Is there a possibility to have it working on an archive.php or category.php, showing only the latest 2 posts on page 1 while maintaining correct pagination? Thanks!
    – Amit
    Commented Dec 15, 2011 at 1:45
  • @Amit: If you replace is_front_page() with is_archive() or is_category(), I think you can get where you need to be.
    – Jan Fabry
    Commented Dec 15, 2011 at 16:46
3

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.

1
  • This works because you only display posts in the "Message of the ... whatever" category, and thus can go to that category page and use the normal paging. I want to show posts from all categories, so this approach will not work for me. You have no place where people can browse through all posts from all categories?
    – Jan Fabry
    Commented Aug 12, 2010 at 11:00
1

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
  • Changing the paged parameter won't break anything else, like the next_posts_link?. Maybe it's better to modify the query in the pre_get_posts hook, so I don't create a new query? And yes, this is WP 3.
    – Jan Fabry
    Commented Aug 12, 2010 at 14:44
  • AFAIK, it shouldn't affect next_posts_link. The only way to find out is to actually try it, of course.
    – john010117
    Commented Aug 12, 2010 at 14:52
  • 1
    Argh, if I try to edit the paged parameter in the pre_get_posts hook, redirect_canonical kicks in and wants to replace the url with the new paged parameter. I can disable redirects in this case, but next_posts_link uses a global $paged variable that gets set to the new value, but I don't know by which code, so it's incorrect.
    – Jan Fabry
    Commented Aug 12, 2010 at 15:25
  • Did you actually try using my code and seeing if it works? I'm not too familiar with the pre_get_posts hook, so I can't be much help there. Also, try to modify the $paged variable directly (ex: $paged = $paged - 1)) if you're worried about next_posts_link().
    – john010117
    Commented Aug 12, 2010 at 15:50
0

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.

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.