<div class="row">
    $currCat = get_category(get_query_var('cat'));
    $cat_name = $currCat->name;
    $cat_id   = get_cat_ID( $cat_name );

    $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $query = array(
            'posts_per_page'=> 3,
            'cat' => $cat_id
    $queryObject = new WP_Query($query);
    while ($queryObject->have_posts()) : $queryObject->the_post();
        $post_category = get_the_category(get_the_ID());

  <div class="col-md-4 module">
      <a class="" href="<?php the_permalink(); ?>">
          <!-- ... -->
  <?php endwhile; ?>
      global $queryObject;
      $big = 999999999; // need an unlikely integer
      echo '<div class="d-flex justify-content-center pagination">';
        echo paginate_links( array(
        'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
        'format' => '?paged=%#%',
        'prev_text' => __('<<'),
        'next_text' => __('>>'),
        'current' => max( 1, get_query_var('paged') ),
        'total' => $queryObject->max_num_pages
        ) );
      echo '</div>';
  • Paginating randomly sorted posts is a recipe for disaster. Each page load will randomise the results differently, so page 1 and page 2 are going to have different results each time meaning that you could see the same results on each page, or end up with posts missing from all pages. Commented Jan 28, 2020 at 10:46
  • Also, in the templates for category archives you shouldn't be using new WP_Query. WordPress has already queried the correct posts, and you should just use while ( have_posts() ) : the_post(); to loop through them. No $queryObject. Commented Jan 28, 2020 at 10:47
  • @JacobPeattie thank you very much. Can you tell me what i need to use instead WP_Query?
    – erzen
    Commented Jan 28, 2020 at 12:31

1 Answer 1


In the template used for category archives you should have no use for new WP_Query. For all the main templates that WordPress loads itself for post archives, WordPress has already queried the correct posts, so you don't need to query them again with WP_Query. For these templates, it's the template's job just to display those posts that have already been queried. This is done using The Loop.

The reason pagination issues are so common with using WP_Query like this is that by default paginate_links() is designed to output pagination links based on the number of posts and posts per page in the 'main query' (the query that WordPress has already performed, and that The Loop will output). So if you're trying to use it with a custom query, and haven't set it up completely perfectly, then the mismatch between your custom query and the main query will give you broken results.

Even if you might be able to fix the pagination to work with your query, you still have a problem with performing an additional query, which will slow down the site, as well as a bunch of redundant logic. The best solution is to implement the template the way WordPress wants you to.

So based on the markup in your your question, all your template should be is:

<div class="row">
    <?php while ( have_posts() ) : the_post(); ?>
        <div class="col-md-4 module">
            <a href="<?php the_permalink(); ?>">
                <!-- ... -->
    <?php endwhile; ?>

    <div class="d-flex justify-content-center pagination">
        echo paginate_links(
                'prev_text' => '<<',
                'next_text' => '>>',

This will output the posts in the current category using your markup, with your pagination controls.

So what if you want to change something about the posts that were queried, such as the order, or number of posts per page? If you search for "query number of posts per page" or "order posts in reverse" you might see a lot of examples using new WP_Query. These answers are demonstrating how to set those properties for a new query, not the existing main query. The process for changing these properties for the main query is a little different.

To change the number of posts or order of the main query, rather than putting this in the template, you need to add a function to your themes functions.php that is hooked into pre_get_posts. This function will give you an opportunity to change the properties of the main query. For example, if you want to change the number of posts per page for category archives, you would add the following:

    function( $query ) {
        // We don't want to affect any back-end queries.
        if ( is_admin() ) {

        // We only want to modify the main query for category archives.
        if ( $query->is_category() ) {
            // Change the number of posts per page.
            $query->set( 'posts_per_page', 3 );

That will change category pages to only display 3 posts per page, but the pagination will continue to work because you've modified the main query that the pagination controls are for.

You'll find a lot more resources on this method of modifying queries by googling "pre_get_posts".

  • Thank you very much this is working. But in same page a have another query. This hook affects, and I'm getting another result. How can I select only one query not all?
    – erzen
    Commented Jan 28, 2020 at 15:20
  • pre_get_posts? It depends. What query do you want to affect, just a single category? Commented Jan 28, 2020 at 15:21
  • I want to affect only posts what post type is product, but in header i'm showing these products too. But when I do this action my products query in header is changing.
    – erzen
    Commented Jan 28, 2020 at 15:36
  • The code in my answer was only targeted at post categories, so whatever change you've made is likely incorrect. I suggest posting a new question with the code you're attempting to use. Commented Jan 28, 2020 at 15:39

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.