Ask your WordPress questions! Pay money and get answers fast! (more info)

How to add pagination links to custom category template? WordPress

  • SOLVED

I have a custom category template which displays the current category's child categories instead of posts. I want to add numbered pagination links to the template for categories with a large number of child categories.

Here are the pagination variables I'm using and the code used to get the current category's child categories:
<?php
$catpage = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$catnum = 5;
$offset = ($catnum * $catpage) - 5;

$cat = get_category( get_query_var( 'cat' ) );
$cat_id = $cat->cat_ID;
$child_categories=get_categories(
array(
'parent' => $cat_id,
'orderby' => 'id',
'order' => 'DESC',
'hide_empty' => '0',
'number' => $catnum,
'offset' => $offset,
'posts_per_page' => 5,
'paged' => $catpage
)
);
?>

This displays 5 child categories. Now how do I add numbered pagination links to the page?

Answers (3)

2016-08-26

Andrea P answers:

Hello,

you'll have to manually build your pagination numbers/links

following your code, it would be something like that:


<?php
$total_terms = count( $child_categories );
$pages = ceil($total_terms/$catnum);


// if there's more than one page
if( $pages > 1 ):
echo '<ul class="paginate">';

// if we're not on the first page, print the previous-link
if ( $catpage > 1 ) {
$prevpage = $catpage - 1;
if ( $prevpage > 1 ) {
echo '<li class="previous-page"><a href="'. get_permalink() .'page/'. $prevpage .'/"> &laquo; </a></li>';
}
else {
echo '<li class="previous-page"><a href="'. get_permalink() .'"> &laquo; </a></li>';
}
}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):
//set class
$class = "page-num";
if ( $pagecount == $catpage ) {
$class .= " current-page";
}
// print number
echo '<li class="'. $class .'"><a href="'. get_permalink() .'page/'. $pagecount .'/">'. $pagecount. '</a></li>';

endfor;

// if there is one more page after the current, print the next-link
if ( $catpage < $pages ) {
$nextpage = $catpage + 1;
echo '<li class="previous-page"><a href="'. get_permalink() .'page/'. $nextpage .'/"> &raquo; </a></li>';

}

echo '</ul>';

endif;

?>



I haven't tested it, so let me know if it works
cheers


jrcollins comments:

Thanks, I'll test it now. Is this numbered pagination?


jrcollins comments:

It has to match the theme's default pagination.


jrcollins comments:

There are no links showing on the page.


Andrea P comments:

Hello,
just to clarify, this code just handles the pagination links, so you need to keep the rest of your code too.
are you doing it?
are you sure that there are supposed to be more than one page? because if there is only one page, the code won't output anything at all.

and it doesn't print the numbers, but could you have a look with your browser inspector and see if it prints any html at all? just to understand where it fails, otherwise it is quite hard to understand.. can you do a few debug testing and try to echo the values of the variables and see what and if they are printed out? by instance the $total_terms and $pages ?

then I've tweaked a bit the code to match your default paginate function structure, but you'll have to take care of that part because I cannot see the actual output and I don't know for sure which classes are appended by your theme..


<?php
$total_terms = count( $child_categories );
$pages = ceil($total_terms/$catnum);


// if there's more than one page
if( $pages > 1 ):
echo '<div class="ft-paginate"><ul class="paginate">';

// if we're not on the first page, print the previous-link
if ( $catpage > 1 ) {
$prevpage = $catpage - 1;
if ( $prevpage > 1 ) {
echo '<li class="previous-page"><a href="'. get_permalink() .'?paged='. $prevpage .'/"><i class="fa fa-angle-left"></i></a></li>';
}
else {
echo '<li class="previous-page"><a href="'. get_permalink() .'"> &laquo; </a></li>';
}
}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):
//set class
$class = "page-num";
if ( $pagecount == $catpage ) {
$class .= " current-page";
}
// print number
echo '<li class="'. $class .'"><a href="'. get_permalink() .'?paged='. $pagecount .'/">'. $pagecount. '</a></li>';

endfor;

// if there is one more page after the current, print the next-link
if ( $catpage < $pages ) {
$nextpage = $catpage + 1;
echo '<li class="previous-page"><a href="'. get_permalink() .'?paged='. $nextpage .'/"><i class="fa fa-angle-right"></i></a></li>';

}

echo '</ul>';
printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $catpage, $pages );
echo '</div>';

endif;
?>


jrcollins comments:

If you read my original question you would have seen that I specifically stated that I need NUMBERED pagination links to match the theme's default links.


jrcollins comments:

You can see from the custom category template that $catnum=3 and on my test site I have a total of 5 child categories so there should be 2 pages. There are no links showing.
Is it not possible to construct a function similar to the theme function?


Andrea P comments:

hello,

the function I posted will print the links as NUMBERS.
what I don't know for sure is which css classes you need to append to the links, and which html structure the pagination is using in your theme.
I've learned some of those infos from your pagination function, but I cannot see everything (by instance I am not sure which class is appended to the current page number in the links), and that's what I am saying that you'll have to double check.

I am sorry but wordpress doesn't have a builtin function to output pagination of categories list. the only way is to custom build it by using offset (like you do in your query) and taking advantage of the variable $paged which is passed by the url.

in any case, I apologize but I really don't like your attitude and manners, and for $10 I have already spent way more time that what you deserve.

best wishes.


jrcollins comments:

I apologise if I caused you to take offense. I was just wondering if it was possible to wrap the code in a function and put it in the functions file rather than having it all in the category template?


jrcollins comments:

Thanks for trying anyway. Too bad it doesn't work.


Andrea P comments:

I had a look and tested on my site and I've realized that the problem was with the counting of the total pages. I was using the $child_categories but that is retrieving only the amount of categories per page, therefore the code was seeing no need for pagination.

I've now corrected it so that I make a new get_categories and retrieve ALL the childs in order to count them and set the total pages correctly.

here its is then, tested and working:


<?php
$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));
$total_terms = count( $total_childs_query );
$pages = ceil($total_terms/$catnum);

// if there's more than one page
if( $pages > 1 ):
echo '<div class="ft-paginate"><ul class="paginate">';

// if we're not on the first page, print the previous-link
if ( $catpage > 1 ) {
$prevpage = $catpage - 1;
if ( $prevpage > 1 ) {
echo '<li class="previous-page"><a href="'. get_permalink() .'?paged='. $prevpage .'"><i class="fa fa-angle-left"></i></a></li>';
}
else {
echo '<li class="previous-page"><a href="'. get_permalink() .'"><i class="fa fa-angle-left"></i></a></li>';
}
}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):
//set class
$class = "page-num";
if ( $pagecount == $catpage ) {
$class .= " current-page";
}
// print number
echo '<li class="'. $class .'"><a href="'. get_permalink() .'?paged='. $pagecount .'">'. $pagecount. '</a></li>';

endfor;

// if there is one more page after the current, print the next-link
if ( $catpage < $pages ) {
$nextpage = $catpage + 1;
echo '<li class="previous-page"><a href="'. get_permalink() .'?paged='. $nextpage .'"><i class="fa fa-angle-right"></i></a></li>';

}

echo '</ul>';
printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $catpage, $pages );
echo '</div>';

endif;
?>


though you will probably have to style the html output in order to match the style of your default pagination.
you can also add classes names or change the html output. if you look at my code, you should be able to spot the html and tweak it as you need.

best wishes.
Andrea


jrcollins comments:

Thank you. I really appreciate the work you've done on this. The links are now showing but when I click on a link to a another page it takes me to a post of one of the child categories instead of to another page.


Andrea P comments:

hi there!

ah ok, yes that makes sense because I've tested it in a page, but if you are into an archive we need to retrieve the current page url in a different way rather than using get_permalink().

try this code then


<?php
$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));
$total_terms = count( $total_childs_query );
$pages = ceil($total_terms/$catnum);


// if there's more than one page
if( $pages > 1 ):

echo '<div class="ft-paginate"><ul class="paginate">';

// if we're not on the first page, print the previous-link
if ( $catpage > 1 ) {
$prevpage = $catpage - 1;
if ( $prevpage > 1 ) {
echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'?paged='. $prevpage .'"><i class="fa fa-angle-left"></i></a></li>';
}
else {
echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'"><i class="fa fa-angle-left"></i></a></li>';
}
}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):
//set class
$class = "page-num";
if ( $pagecount == $catpage ) {
$class .= " current-page";
}

// print number
echo '<li class="'. $class .'"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'?paged='. $pagecount .'">'. $pagecount. '</a></li>';

endfor;

// if there is one more page after the current, print the next-link
if ( $catpage < $pages ) {
$nextpage = $catpage + 1;
echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'?paged='. $nextpage .'"><i class="fa fa-angle-right"></i></a></li>';

}

echo '</ul>';
printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $catpage, $pages );
echo '</div>';


endif;
?>


Andrea P comments:

ah! as you already store the category id into a var, you could substitute


get_query_var( 'cat' )


with

$cat_id


so the various links will be built with this as base (change it in the few places where it appears):

get_term_link( $cat_id, get_query_var( 'taxonomy' ) )

the code will work anyways, but this would be more efficient. ;)


jrcollins comments:

Hi, I made a few other changes to the code and it seems to be working ok now. Here's what I have:

<?php

$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));

$total_terms = count( $total_childs_query );

$pages = ceil($total_terms/$catnum);
// if there's more than one page

if( $pages > 1 ):

echo '<div class="ft-paginate"><ul class="paginate">';

// if we're not on the first page, print the previous-link

if ( $catpage > 1 ) {

$prevpage = $catpage - 1;

if ( $prevpage > 1 ) {

echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'/page/'. $prevpage .'"><i class="fa fa-angle-left"></i></a></li>';
}

else {

echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'"><i class="fa fa-angle-left"></i></a></li>';
}

}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):

//set class

$class = "page-num";

if ( $pagecount == $catpage ) {

$class .= " current-page";

}

if ( $pagecount == 1 ) {

echo '<li class="'. $class .'"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'">'. $pagecount. '</a></li>';
}

else {

// print number

echo '<li class="'. $class .'"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'/page/'. $pagecount .'">'. $pagecount. '</a></li>';
}

endfor;

// if there is one more page after the current, print the next-link

if ( $catpage < $pages ) {

$nextpage = $catpage + 1;

echo '<li class="previous-page"><a href="'. get_term_link( get_query_var( 'cat' ), get_query_var( 'taxonomy' ) ) .'/page/'. $nextpage .'"><i class="fa fa-angle-right"></i></a></li>';

}

echo '</ul>';

printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $catpage, $pages );

echo '</div>';

endif;

?>


This works if the permalink settings are set to "postname". So, if I change the permalink settings the navigation links will no longer work but that's not a problem anyway.

I've also noticed that in the theme's default page navigation links, if the current page is more than 2 links from the first or last page link, the intermediary links change to a single link showing an ellipsis (see screenshot). It might be easier to change the theme's pagination settings to match rather than the other way around.

Is it possible to wrap the code in a function? That way I could generate the links with a single line of code in the template.


jrcollins comments:

I added an extra "if - else" statement for printing the numbers so that "/page/1/" isn't added to the category "home" page.


jrcollins comments:

Did you get my last message? I would still like to know if it's possible to create a function from the code.


Andrea P comments:

Hello,

I have optimized the code a bit and made it as a function.
you can put this in your functions.php


function bwd_custom_categories_pagination( $catnum ) {

$catpage = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$catid = get_query_var( 'cat' );
$base_url = get_term_link( $catid, get_query_var( 'taxonomy' ) );
$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));
$total_terms = count( $total_childs_query );
$pages = ceil($total_terms/$catnum);

// if there's more than one page
if( $pages > 1 ):
echo '<div class="ft-paginate"><ul class="paginate">';

// if we're not on the first page, print the previous-link
if ( $catpage > 1 ) {
$prevpage = $catpage - 1;
if ( $prevpage > 1 ) {
echo '<li class="previous-page"><a href="'. $base_url .'/page/'. $prevpage .'"><i class="fa fa-angle-left"></i></a></li>';

}
else {
echo '<li class="previous-page"><a href="'. $base_url .'"><i class="fa fa-angle-left"></i></a></li>';
}
}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):
//set class
$class = "page-num";
if ( $pagecount == $catpage ) {
$class .= " current-page";
}

if ( $pagecount == 1 ) {
echo '<li class="'. $class .'"><a href="'. $base_url .'">'. $pagecount. '</a></li>';
}
else {
// print number
echo '<li class="'. $class .'"><a href="'. $base_url .'/page/'. $pagecount .'">'. $pagecount. '</a></li>';
}

endfor;

// if there is one more page after the current, print the next-link
if ( $catpage < $pages ) {
$nextpage = $catpage + 1;
echo '<li class="previous-page"><a href="'. $base_url .'/page/'. $nextpage .'"><i class="fa fa-angle-right"></i></a></li>';
}

echo '</ul>';
printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $catpage, $pages );
echo '</div>';

endif;

}


and then put this snippet in the template file


<?php bwd_custom_categories_pagination( $catnum ); ?>


cheers


jrcollins comments:

Thanks, that's exactly what I was looking for but there seems to be a problem with the function. There's nothing showing on the page and no html output.

This is the code I'm using now (I've changed the HTML to match the theme's):

<?php
// Start of Pagination
$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));

$total_terms = count( $total_childs_query );

$pages = ceil($total_terms/$catnum);

$base_url = get_term_link( $cat_id, get_query_var( 'taxonomy' ) );

// if there's more than one page

if( $pages > 1 ):

echo '<div class="ft-paginate">';
echo '<nav class="navigation pagination" role="navigation">';
echo '<div class="nav-links">';

// if we're not on the first page, print the previous-link

if ( $catpage > 1 ) {

$prevpage = $catpage - 1;

if ( $prevpage > 1 ) {

echo '<a class="prev page-numbers" href="' . $base_url . '/page/' . $prevpage . '"><i class="fa fa-angle-left"></i></a>';
}

else {

echo '<a class="prev page-numbers" href="' . $base_url . '"><i class="fa fa-angle-left"></i></a>';
}

}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):

//set class

$class = "page-numbers";

if ( $pagecount == $catpage ) {

$class .= " current";

}

if ( $pagecount == $catpage ) {

echo '<span class="' . $class . '">' . $pagecount . '</span>';
}

else if ( $pagecount == 1 ) {

echo '<a class="prev' . $class . '" href="' . $base_url . '">' . $pagecount . '</a>';

}

else {

echo '<a class="' . $class . '" href="' . $base_url . '/page/' . $pagecount . '">' . $pagecount . '</a>';

}

endfor;

// if there is one more page after the current, print the next-link

if ( $catpage < $pages ) {

$nextpage = $catpage + 1;

echo '<a class="next' . $class . '" href="' . $base_url . '/page/' . $nextpage . '"><i class="fa fa-angle-right"></i></a>';

}

echo '</div>';
echo '</nav>';

printf( '<span class="total-pages">' . esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) . '</span>', $catpage, $pages );

echo '</div>';

endif;
// End of Pagination
?>


jrcollins comments:

Ok, this is the final version of the code. This works perfectly and matches the theme's styles exactly.

<?php
// Start of Pagination
$total_childs_query = get_categories( array( 'parent' => $cat_id, 'hide_empty' => '0' ));

$total_terms = count( $total_childs_query );

$pages = ceil($total_terms/$catnum);

$base_url = get_term_link( $cat_id, get_query_var( 'taxonomy' ) );

// if there's more than one page

if( $pages > 1 ):

echo '<div class="ft-paginate">';
echo '<nav class="navigation pagination" role="navigation">';
echo '<h2 class="screen-reader-text">Posts navigation</h2>';
echo '<div class="nav-links">';

// if we're not on the first page, print the previous-link

if ( $catpage > 1 ) {

$prevpage = $catpage - 1;

if ( $prevpage > 1 ) {

echo '<a class="prev page-numbers" href="' . $base_url . '/page/' . $prevpage . '"><i class="fa fa-angle-left"></i></a>';
}

else {

echo '<a class="prev page-numbers" href="' . $base_url . '"><i class="fa fa-angle-left"></i></a>';
}

}

for ($pagecount=1; $pagecount <= $pages; $pagecount++):

//set class

$class = "page-numbers";

if ( $pagecount == $catpage ) {

$class .= " current";

}

if ( $pagecount == $catpage ) {

echo '&nbsp;<span class="' . $class . '"><span class="screen-reader-text">Page</span>' . $pagecount . '</span>';
}

else if ( $pagecount == 1 ) {

echo '&nbsp;<a class="' . $class . '" href="' . $base_url . '"><span class="screen-reader-text">Page</span>' . $pagecount . '</a>';

}

else {

echo '&nbsp;<a class="' . $class . '" href="' . $base_url . '/page/' . $pagecount . '"><span class="screen-reader-text">Page</span>' . $pagecount . '</a>';

}

endfor;

// if there is one more page after the current, print the next-link

if ( $catpage < $pages ) {

$nextpage = $catpage + 1;

echo '&nbsp;<a class="next' . $class . '" href="' . $base_url . '/page/' . $nextpage . '"><i class="fa fa-angle-right"></i></a>';

}

echo '</div>';
echo '</nav>';

printf( '<span class="total-pages">' . esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) . '</span>', $catpage, $pages );

echo '</div>';

endif;
// End of Pagination
?>


The only difference is the ellipsis which is controlled by the end_size and mid_size parameters in the paginate_links function. I'm sure it's possible to replicate this but it's not worth the effort as far as I'm concerned.

2016-08-26

Arnav Joy answers:

can you show me url of the page where it is implemented ?

so you want to add category pagination ???


jrcollins comments:

Hi, I'm working on the site offline. The theme I'm using is Codilight lite (child theme). If you like I could send you the child theme files. That's if you have a local Wordpress installation.


Arnav Joy comments:

ok send me files at : [email protected]

and also show me screenshot where it is present.


jrcollins comments:

I sent the files. Do you have a local Wordpress installation? If so you can install the free theme (Codilight lite) and use the files I sent you.


jrcollins comments:

Here's a screenshot. You can see the pagination links at the bottom left. That's how I want the links to look on the custom category page.


Arnav Joy comments:

ok i will check.


jrcollins comments:

Here's the function used to generate the theme's default pagination links:
function codilight_lite_custom_paginate() {
global $wp_query;
$total_pages = $wp_query->max_num_pages;
$big = 999999999;
$translated = __( 'Page', 'codilight-lite' );

if ($total_pages > 1){
$current_page = max(1, get_query_var('paged'));
echo '<div class="ft-paginate">';
echo paginate_links(array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',
'prev_next' => True,
'prev_text' => '<i class="fa fa-angle-left"></i>',
'next_text' => '<i class="fa fa-angle-right"></i>',
'current' => $current_page,
'total' => $total_pages,
'before_page_number' => '<span class="screen-reader-text">'.$translated.' </span>'
));
//echo '<span class="total-pages">Page '. $current_page .' of '. $total_pages .'</span>';
printf( '<span class="total-pages">'. esc_html__( 'Page %1$s of %2$s', 'codilight-lite' ) .'</span>', $current_page, $total_pages );
echo '</div>';
}
}
endif;

2016-08-26

Bob answers:

Can you please test this one.

Replace 67 with your parent category id
Do necessary changes at print_r($term); using $term.




$taxonomyName = "category";
$terms = get_terms($taxonomyName, 'parent=67');

function objectToArray($d) {
if (is_object($d)) {

$d = get_object_vars($d);
}

if (is_array($d)) {

return array_map(__FUNCTION__, $d);
}
else {
// Return array
return $d;
}
}

wp_reset_query();

$rows_per_page = 3;
$current = (intval(get_query_var('paged'))) ? intval(get_query_var('paged')) : 1;

//echo "current ==> ".$current;

global $wp_rewrite;

$pagination_args = array(
'base' => @add_query_arg('paged','%#%'),
'format' => '',
'total' => ceil(count($terms)/$rows_per_page),
'current' => $current,
'show_all' => false,
'type' => 'list',
'prev_next' => true,
'prev_text' => __('«'),
'next_text' => __('»')
);

if( $wp_rewrite->using_permalinks() )
$pagination_args['base'] = user_trailingslashit( trailingslashit( remove_query_arg('s',get_pagenum_link(1) ) ) . 'page/%#%/', 'paged');

if( !empty($wp_query->query_vars['s']) )
$pagination_args['add_args'] = array('s'=>get_query_var('s'));

$start = ($current - 1) * $rows_per_page;
$end = $start + $rows_per_page;
$end = (count($terms) < $end) ? count($terms) : $end;

echo '<br />';
for ($i=$start;$i < $end ;++$i ) { ?>
<?php $term = $terms[$i] ?>

<div id="post-<?php the_ID();?>" class="posts">

<?php // do what you want to do with your term
print_r($term);
?>

</div>

<?php } ?>

<?php
echo "<div class='pagination scenes-pagination'>";
echo paginate_links($pagination_args);
echo "</div>";
?>


jrcollins comments:

Thanks but someone is already helping me with this.


Bob comments:

You mean helping with above posted code?

or helping with your issue?

It's ok, just try to test it when you are comfertable with it.


jrcollins comments:

Yes, someone else is helping me with it.