List categories by letter

The code below is for a template for the WP 2.9 default theme that lists categories by the first letter of the category name.

An updated version of this code, with the capability to list terms of any taxonomy is shown in this post.

<?php
/**
 * @package WordPress
 * @subpackage Default_Theme
 */
/*
Template Name: listcatsbyletter
*/
?>
<?php /*
 Author: Mac McDonald
 Contact at BluegrassMiataClub.com using About->Contact Us form.

 This program creates a list of categories as links to the archive for
 each category.

 Set $hide_uncategorized = false; to show the uncategorized category.
     $hide_description = true; to hide the description of each category.
     $limit = the number of categories (not including Letters) per page.
     $range = number of page links in the nav bar. (5 is a good number).
*/?>

<?php get_header(); ?>

<?php
$hide_uncategorized = true;
$hide_description = false;
$limit = 25;  // Show this many entries per page
$range = 5;  // Show this many nav bar page links (other than first & last).
$args = array('orderby' => 'name', 'order' => 'ASC');
if ($hide_uncategorized) $args['exclude'] = '1';
$categories = get_categories($args);
if ($categories) :
   // For some unknown reason, $categories has no [0] entry at times, so renumber.
   $categories = array_merge($categories,array());
   if (isset($_GET['page'])) {
      $page = $_GET['page'];
   } else {
      $page = 1;
   }
   $start = ($page - 1) * $limit;
   $currletter = '';
   echo '<ul class="category_list">';
   for ($i=$start;$i<($start + $limit);++$i) {
      if ($i < sizeof($categories)) {
         $cat =  $categories[$i];
         $catletter = strtoupper(substr($cat->name,0,1));
         if ($currletter != $catletter) {
            if ($currletter != '') echo '</ul>';
            $currletter = $catletter;
            echo "<h2> - $catletter - </h2>";
            echo '<ul>';
         }
         echo '<li class="category_entry">Category: <a href="' . get_category_link( $cat->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $cat->name ) . '" ' . '>' . $cat->name.'</a> </p> ';
         if (!$hide_description) echo '<p>Description: '. $cat->description . '</p>';
         echo '</li>';
      }
   }
   echo '<br /><br />';
   echo _cat_paginate(sizeof($categories),$limit,$range);
   echo '</ul>';
else:
   echo '<h2></h2>';
   echo 'There are no Categories to list';
endif;?>

<?php get_footer(); ?>

<?php function _cat_paginate($numrows,$limit=10,$range=7) {

   $pagelinks = "<div class=\"pagelinks\">";
   $currpage = $_SERVER['PHP_SELF'] . "?" . $_SERVER['QUERY_STRING'];
   if ($numrows > $limit) {
      if(isset($_GET['page'])){
         $page = $_GET['page'];
      } else {
         $page = 1;
      }
      $currpage = $_SERVER['PHP_SELF'] . "?" . $_SERVER['QUERY_STRING'];
      $currpage = str_replace("&page=".$page,"",$currpage);
      if($page == 1){
         $pagelinks .= "<span class=\"pageprevdead\">&laquo PREV </span>";
      }else{
         $pageprev = $page - 1;
         $pagelinks .= "<a class=\"pageprevlink\" href=\"" . $currpage .
               "&page=" . $pageprev . "\">&laquo PREV </a>";
      }
      $numofpages = ceil($numrows / $limit);
      if ($range == "" or $range == 0) $range = 7;
      $lrange = max(1,$page-(($range-1)/2));
      $rrange = min($numofpages,$page+(($range-1)/2));
      if (($rrange - $lrange) < ($range - 1)) {
         if ($lrange == 1) {
            $rrange = min($lrange + ($range-1), $numofpages);
         } else {
            $lrange = max($rrange - ($range-1), 0);
         }
      }
      if ($lrange > 1) {
         $pagelinks .= "<a class=\"pagenumlink\" " .
            "href=\"" . $currpage . "&page=" . 1 .
            "\"> [1] </a>";
         if ($lrange > 2) $pagelinks .= "&nbsp;...&nbsp;";
      } else {
         $pagelinks .= "&nbsp;&nbsp;";
      }
      for($i = 1; $i <= $numofpages; $i++){
         if ($i == $page) {
            $pagelinks .= "<span class=\"pagenumon\"> [$i] </span>";
         } else {
            if ($lrange <= $i and $i <= $rrange) {
               $pagelinks .= "<a class=\"pagenumlink\" " .
                        "href=\"" . $currpage . "&page=" . $i .
                        "\"> [" . $i . "] </a>";
            }
         }
      }
      if ($rrange < $numofpages) {
         if ($rrange < $numofpages - 1) $pagelinks .= "&nbsp;...&nbsp;";
            $pagelinks .= "<a class=\"pagenumlink\" " .
               "href=\"" . $currpage . "&page=" . $numofpages .
               "\"> [" . $numofpages . "] </a>";
      } else {
         $pagelinks .= "&nbsp;&nbsp;";
      }
      if(($numrows - ($limit * $page)) > 0){
         $pagenext = $page + 1;
         $pagelinks .= "<a class=\"pagenextlink\" href=\"" . $currpage .
                    "&page=" . $pagenext . "\"> NEXT &raquo;</a>";
      } else {
         $pagelinks .= "<span class=\"pagenextdead\"> NEXT &raquo;</span>";
      }

   }
$pagelinks .= "</div>";
return $pagelinks;
}
?>

17 Responses to List categories by letter

  • Filip Salamic says:

    Hello there,
    I was wondering if there was a way to list these categories in 2-3 columns?

  • Paulo says:

    Hi! This is very useful! I only have one question: I don’t want to have a limit, I want all categories. I changed the value on:

    $limit = 25

    But I would prefer not having a limit at all. Thanks!

    • Mac McDonald says:

      The limit is used in several places, so it would not be easy to totally eliminate it. The easiest thing to do is what you have already done – just set $limit to a very large number:

      $limit = 99999;

  • Mac McDonald says:

    I can’t be sure this is what you want, but try changing this:

    $catletter = strtoupper(substr($cat->name,0,1));

    to this:

    $catletter = strtoupper(substr($cat->name,0,1));
    $catletter = mb_convert_encoding($catletter,'UTF-8', mb_detect_encoding($catletter) ) ;
    
    • It just shows nothing, returning – – instead of -E-
      But would it be possible to get the letter of the slug instead of name ? Knowing that the slug has no accent, it could be a solution.

      • Mac McDonald says:

        That is certainly worth a try.

        • That’s not really clean, but it does what I need :

          if ($currletter != $catletter) {
          if ($currletter != '') echo '';
          $currletter = $catletter;
          $catletter = mb_convert_encoding($catletter,'UTF-8', mb_detect_encoding($catletter) ) ;
          if ($catletter == '') {
          echo " - E - ";
          }
          else echo " - $catletter - ";
          echo '';
          }

          Thanks for your help!

  • One more question ^^
    My list has some accent and it result the “?”
    I tried this
    if ($currletter != $catletter) {
    if ($currletter != '') echo '';
    $currletter = $catletter;
    if ($catletter == 'é'){
    echo " - E - ";
    }
    else {
    echo " - $catletter - ";
    }
    echo '';
    }

    But it obviously doesn’t work.
    Do you have any idea how I can convert an É in E ?
    Thank you for your time.

  • I’m trying to get your list with a custom taxonomy. It works when adding taxonomy in the args but the links are not working anymore. It links to the page itself. I think it has to be with the get_category_link but when I change it for get_term_link it breaks everything.
    Do you have any clue on how I can adapt your list for custom taxonomy ?
    Thanks

    • Mac McDonald says:

      get_term_link() should work if you pass it the entire object rather than the ID.

      I tested by changing

      $categories = get_categories($args);

      to

      $categories = get_terms('mytaxonomy',$args);

      and changing

      get_category_link( $cat->term_id )

      to

      get_term_link( $cat )

  • Amazing! Thanks.
    Note that you have a useless div at line 66

  • Daniel says:

    Mac how can I display only posts from one category and their subcategories ? I have about 500 categories so better than exclude 400 would be better to include one category which contains 100 subcategories below

    • Mac says:

      If I read this Codex article right, WordPress does not seem to have a parameter to get_categories that will let you show a parent and all its children.

      According to the article, you can use the ‘child_of’ parameter to get the children, but it does not say that will also list the parent.

      You can try adding this line just before the call to get_categories:

      $args["child_of"] = 99;

      Replace the 99 with your parent category ID.

Leave a Reply

Your email address will not be published. Required fields are marked *

*