9

I want to display an archive page with pagination that lists all the categories on my site, and each link goes to that particular category archive page. So this would be like an archive page of category archives.

Each category on my site has a custom thumbnail created manually to match the category's permalink. I already have a layout setup to display all the categories but I'm doing this with a custom page template, so there's no pagination. This means all categories display on a single page which is a tad annoying(I have 100+ categories).

My current archive is setup with a specific custom page template name page-catlist.php but I'm willing to change this to any other type of template file.

Here's the current code I'm using to output all categories on one page:

$args = array(
  'orderby' => 'name',
  'order' => 'ASC'
);
$cats      = get_categories( $args );
$thm_pre   = 'http://example.com/images/thumbs/';
$thm_end   = '.png';

foreach($cats as $cat) {
    $thumbnail = $thm_pre.$cat->slug.$thm_end;
    // output the loop HTML here
    // basically a list of category names & thumbs 
    // all linked to the cat URL by get_category_link()
}

I'm hoping there's a better way to do this so that I can add natural pagination, ideally with WP-PageNavi. Any help would be greatly appreciated!

2
  • That's gonna be a lot of effort ;)
    – Sumit
    May 27 '16 at 18:56
  • @Sumit it is actually quite easy with about no effort at all ;-) May 28 '16 at 8:32
2

Paging a list of terms/categories/tags are quite easy, and to achieve that, you need minimal info.

Lets look at we need

  • the amount of terms

  • the amount of terms per page

  • get_terms() (Just note, the usage of get_terms() have changed in version 4.5). You can also use get_categories() if you wish, get_categories() is just a wrapper function for get_terms()

So first we need to count the amount of terms. For this, we will use the count parameter in get_terms()

NOTE:

  • All code is untested and requires at least

    • PHP 5.4

    • WordPress 4.5

You can easily convert this to work with older versions of PHP and WordPress

$taxonomy   = 'category';
$term_count = get_terms( 
    [
        'taxonomy'  => $taxonomy,
        'fields'    => 'count'
    ]
);

Now that we know the amount of terms, we can set the amount of terms we need per page, lets say 10

$terms_per_page = 10;

From the above, we can now work out how many pages we will have. The value here will be passed to the requires pagination function, in your case, to wp_pagenavi()

$max_num_pages = ceil( $term_count/$terms_per_page );

In this case, you would pass $max_num_pages to your pagination function

The next part would be to calculate our offset. We only want to retrieve the relevant amount of terms per page to keep things optimized. We do not need all 100+ terms per page. Querying only the needed 10 is much faster. So, we need to know on which page we are, are from that, we will calculate an offset. This will be passed to get_terms(), and will tell get_terms() how many terms to skip from the initial starting point.

Once have that, we must also tell get_terms() to only return 10 terms. Let look at the code for this piece

$current_page = get_query_var( 'paged', 1 ); // Change to 'page' for static front page
$offset       = ( $terms_per_page * $current_page ) - $terms_per_page;
$terms        = get_terms(
    [
        'taxonomy' => $taxonomy,
        'order'    => 'ASC',
        'orderby'  => 'name',
        'number'   => $terms_per_page,
        'offset'   => $offset
    ]
);

You will only have 10 terms per page according to pagination. You can now just loop normally through your terms

Just a note, you would want to make sure that you actually have terms returned from your get_terms() function.

3
  • Cool ;) But I did not how to build pagination markup? wp_pagnavi() will really work in this case ?
    – Sumit
    May 28 '16 at 13:34
  • 1
    @Sumit this would work with next_posts_link(), previous_posts_link() and paginate_links(). It would also work with any paging function where you can pass an integer value to the function, like my paging function here. As far as for wp_pagenavi(), I cannot say yes or no as I really have no idea how that function works, you will need to test it out. In my code above, $max_num_pages holds the amount of pages, it is an integer value, it is this variable you need to pass to functions to calculate pagination May 29 '16 at 10:35
  • 1
    Special thanks to both you and @cjbj as I think both of these solutions could certainly work. After looking around I've found some WP-PageNavi stuff explaining how it can work... Granted it's always possible to roll a custom pagination so either way I think these solutions are the best. May 30 '16 at 14:07
1

I'm not familiar with WP-PageNavi, but I suspect it assumes to be dealing with posts, so it might easily screw up if you use it on a loop like yours. Perhaps the css might still be helpful in styling your html. Anyway, setting up your own pagination is not that difficult.

First, you need to know how many categories there are:

$cat_amounts=count($cats);

Next you need to determine how many items per page you want:

$cats_per_page=20;

This will give you the amount of pages:

$max_pages=ceil($cat_amounts/$cats_per_page);

The third piece of information you need is the page you are on. You can keep track of this by introducing a query_var Your url will then look something like this: www.example.com/yourcatpage?catpage=2

Before you start the loop, you need to know which page is called:

$page_called=get_query_var ( $catpage, 1 )

From this you can call the first element you want to display:

$first_element=($page_called-1)*$cats_per_page)

and the last one:

$last_element=$page_called*$cats_per_page-1;

The last page may contain less than $cats_per_page categories, so additionally you need:

if ($last_element > $cat_amounts) $last_element = $cat_amounts;

Now, loop through the desired elements of $cats:

for ($i=$first_element;$i=<$last_element;$i++) {
    //do your thing with $cats[$i];
}

After the loop you can use the variables to generate previous/next tags or nay other type of navigation.

Beware that I didn't actually test this code. I may have made some mistakes when taking into account that the first element in an array has key 0.

2
  • There is a much easier approach which is cleaner and faster ;-) May 28 '16 at 8:34
  • Actually, I don't think our approaches are that different. You let MySQL handle the offset, I leave it to PHP.
    – cjbj
    May 28 '16 at 10:34

Your Answer

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

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