I want to be able to change the amount of post shown on each archive page on a per category basis. Is there something I can change in the loop code or a plugin that gives me that ability?

Thank you SE community.


paste this in your theme function.php file

add_filter('pre_get_posts', 'Per_category_basis');

function Per_category_basis($query){
    if ($query->is_category) {
        // category named 'books' show 12 posts
        if (is_category('books'){
            $query->set('posts_per_page', 12);
        // category With ID = 32 show only 5 posts
        if (is_category('32'){
            $query->set('posts_per_page', 5);
    return $query;


explanation: first we check if its actually a category because we don't want to change anything else. if so we check to see and change the number of posts to show, on the first one we check by category name 'books' and assign the value of 12 posts_per_page the second one is by category id of '32' and we assign the value of 5 posts_per_page just to show you that you can use either one. and you can just add as many checks and assignments.

  • You might consider using 'posts_per_archive_page' instead, as that over-rides posts_per_page in is_archive() or is_search() context, and may save on a conditional or two :) – Tom Auger Oct 27 '11 at 21:32
  • Is there a reason you prefer to use the 'pre_get_posts' over 'request' filter? – Tom Auger Oct 27 '11 at 21:33
  • No reason its just proper use of these hooks and there parameters – Bainternet Oct 28 '11 at 19:01
  • 1
    Do note that with pre_get_posts you're targetting EVERY query (inluding get_pages(), get_posts(), query_posts() etc). This will affect, for example, sidebar widgets that may query the 'books' category, as per your example. request does not run this risk as it only gets applied as part of the initial request query. I'm sure you already knew this, just adding this in case anyone else stumbles across the thread. – Tom Auger Oct 28 '11 at 19:24
  • For completeness (and because I'm already being pedantic), there's also the parse_request action that can be hooked into, which has the added benefit of giving you a reference to the $wp object so you can do things like check against the original $_POST query vars if you want to limit pages based on the request. – Tom Auger Oct 28 '11 at 19:27

Bainternet's solution did not work in my case, even though it helped me figure out how to do it correctly.

The solution is to take the parameter by reference, since else it will just make a copy of the query object.

add_action('pre_get_posts', 'custom_per_page');

function custom_per_page(&$query) {
if (is_post_type_archive('custom_post_type_name')) {
    $query->set('posts_per_page', 4);
  • 1
    It is obviously neat if things work for you, but I cannot imagine it to be necessary to pass $query by reference. – Johannes Pille Apr 3 '13 at 8:55
  • This is not a filter. pre_get_posts is an action – Dragos Apr 3 '13 at 12:43
  • 1
    And that is to say what? – Johannes Pille Apr 3 '13 at 13:28

If you're looking for a plugin to do this, you can use @ChipBennett Different Posts Per Page plugin

  • And this was downvoted because....? – Tom Auger Jul 5 '16 at 3:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy