Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Category Functions for WordPress

[ Downtown Seattle WA 2012 ] My previous theme sports the now-infamous colorized categories, which aim to help visitors navigate featured content. In addition to the colors, featured categories display contextually relevant navigation, popular posts, and related tags. It’s a great way to improve organization and get more of your content in front of the visitor.

To make it happen, a variety of tasty WordPress code snippets are used, including versatile theme functions that enable getting the first category link, displaying sub-categories of the current category, displaying popular posts per category, related tags, and more. In this post, you get the entire collection, plucked directly from my theme’s functions.php file and mixed with everything needed to enhance WordPress’ category functionality for your own projects.

Menu

Custom body_class & post_class

WordPress makes it easy to add class to your web pages. Class attributes enable you to more easily and efficiently style your pages using CSS. Using the body_class() and post_class() functions, it’s possible to include any class names virtually anywhere in your WordPress theme. Note that body_class() is generally applied to the <body> element, while post_class() is more flexible, aiming for a post-enclosing element such as <article> or whatever makes sense.

There are (at least) two ways to add classes using these functions. First, if you just want to add a class name to all pages on your site, simply include it within the template tag, like so:

<body <?php body_class('custom-body-class'); ?>>
<article <?php post_class('custom-post-class'); ?>>

When working with categories, it’s often necessary to add classes conditionally, which is done by filtering the function via the theme’s functions.php file. Here is a simple example showing each function:

// add custom body class
add_filter('body_class', 'add_custom_body_class');
function add_custom_body_class($classes) {
	if (is_page()) $classes[] = 'custom-body-class';
	return $classes;
}
// add custom post class
add_filter('post_class', 'add_custom_post_class');
function add_custom_post_class($classes) {
	if (is_page()) $classes[] = 'custom-post-class';
	return $classes;
}

These functions respectfully add custom-body-class to the <body> element, and custom-post-class to the <article> element (or whatever element chosen for post_class). This is entirely plug-n-play functionality, just pick your class names and you’re all set. Of course, more advanced filtering is possible. For example, in my theme with the color-coded categories, custom classes are required for a multitude of different page views. Fortunately, we can combine the power of WordPress conditional tags with body_class() and post_class() filtering to get as specific as needed. To share an example of how elaborate it can get, here is the actual code used for my previous theme:

// custom body_class treatments
add_filter('body_class','body_class_names');
function body_class_names($classes) {
	// single
	if ((is_page()) || (is_404())) $classes[] = 'single';
	if (is_single()) $category = get_the_category(); $cat_slug = $category[0]->slug; $classes[] = 'single-feat-cat-'. $cat_slug;
	if ((is_single()) && (in_category(array('wordpress', 'security', 'seo', 'css', 'php', 'html', 'javascript', 'htaccess')))) $classes[] = 'single-feat-cat';
	// cats
	if (is_category(array('media', 'web-design'))) $classes[] = 'cat-parent';
	if (is_category(array('blogging', 'graphics', 'music', 'photos', 'tech', 'writing'))) $classes[] = 'media-sub-cat';
	if (is_category(array('wordpress', 'security', 'seo', 'css', 'php', 'html', 'javascript', 'htaccess'))) $classes[] = 'featured-cat';
	if ((is_author() && !is_paged()) || is_category(array('blogging', 'graphics', 'music', 'photos', 'tech', 'writing', 'media', 'web-design'))) $classes[] = 'cat-other';
	// archive
	if (is_year()) $classes[] = 'archive-year';
	return $classes;
}

// custom post_class treatments
add_filter('post_class','post_class_names');
function post_class_names($classes) {
	if (!in_category(array('wordpress', 'security', 'seo', 'css', 'php', 'html', 'javascript', 'htaccess'))) $classes[] = 'regular-cat';
	$category = get_the_category(); $cat_slug = $category[0]->slug; $classes[] = 'feat-cat-'. $cat_slug;
	if (is_page()) $classes[] = 'post';
	return $classes;
}

I’ll spare everyone the drama of explaining all of that, but suffice it to say that you can combine different conditional tags to target virtually any type of page. Very useful when working with WordPress categories.

Category-specific post thumbnails

WordPress automates the process of adding post thumbnails (featured images) to your posts, but currently there is no built-in way to choose featured images for categories. The easiest way of including custom images for your categories is to add something like this to the WordPress loop:

<?php // category featured image
$category = get_the_category(); 
echo '<img src="'. get_bloginfo('template_directory') .'/file/path/'. $category[0]->cat_name .'.png">';
?>

That works a treat, just specify the correct path to your category images directory and maybe change the file extension if you’re using a format other than PNG. As-is, the code uses the category name as the file name, so make sure you name your images accordingly. Note that categories containing blank spaces and other weird characters present issues on certain setups, so to workaround this you may want to try replacing $category[0]->cat_name with $category[0]->category_nicename or similar.

Another option is to display the featured category image only if a post thumbnail doesn’t exist. To do so, add the following code to your theme’s functions.php file:

// category-specific post thumbnails
function category_specific_post_thumbnails() {
	if ((function_exists('has_post_thumbnail')) && (has_post_thumbnail())) { 
		the_post_thumbnail('thumbnail');
	} else {
		$category = get_the_category();
		echo '<img src="'. get_bloginfo('template_directory') .'/file/path/'. $category[0]->cat_name .'.png">'; 
	}
}

As before, specify the correct path to your properly named category images and you’re all set. Once the code is place, you may display the output anywhere within the loop using the following template tag:

<?php category_specific_post_thumbnails(); ?>

For more advanced configurations and customizations, you’re probably better off going with a category image plugin.

Display link to first category, parent category, both

There are a number of ways to display all categories for each post, but sometimes you just want to display the first category when multiple are available. This is easily done with the following line placed in the loop:

$category = get_the_category();
echo $category[0]->name;

To make it a link, we call upon get_category_link():

$category = get_the_category();
$category_link = get_category_link($category->term_id);
echo '<a href="'. $category_link .'">'. $category[0]->name .'</a>';

This works great, but for my previous theme I want to display a link to the parent category, if it exists, so I added this to my functions.php file:

// display first category
function first_category_link() {
	$category = get_the_category();
	$category_link = get_category_link($category->term_id);
	$parent = get_cat_name($category[0]->category_parent);
	$parent_ID = get_cat_ID($parent);
	$parent_link = get_category_link($parent_ID);
	if ($parent_link) {
		echo '<a href="'. $parent_link .'">'. $parent .'</a>';
	} else {
		echo '<a href="'. $category_link .'">'. $category[0]->name .'</a>';
	}
}

And then call the function by placing the following template tag anywhere within the WordPress loop:

<?php first_category_link(); ?>

No editing is required for this snippet to work, although you may want to fiddle with the markup. You know, to make it just perfect for your project.

Display sub-categories of current category

The next trick I needed to do involves displaying the sub-categories of whatever current category the visitor happened to be viewing. This provides context to the user and facilitates expedient site navigation. To add this functionality to your theme, place the following in functions.php:

// display sub-categories of current category
function display_sub_categories() {
	$current_cat = get_query_var('cat');
	$args = array('child_of'=>$current_cat);
	$categories = get_categories($args);
	if (!empty($categories)) {
		echo '<ul>';
		foreach ($categories as $category) {
			echo '<li><a href="'.$category->slug.'">'. $category->name .'</a></li>';
		}
		echo '</ul>';
	} else {
		// fallback for when no subcategories are available
	}
}

Once this code is in place, call the function anywhere in your theme using the following template tag:

<?php display_sub_categories(); ?>

This method is easily modified to produce just about any category list you could imagine. To get an idea of the possibilities, visit the WordPress Codex and check out the many parameters at your disposal when using the get_categories() function. Powerful stuff!

Popular posts per category

Popular posts are good, no question about that, but for sites (such as this one) with lots of content in different categories, you can take it a step further and provide top posts that are relevant to the current category. So for example, when a visitor is viewing your WordPress Category, you can share with them the most popular WordPress posts instead of a bunch of stuff that might be less interesting.

To display popular posts per category, add the following snippet to your theme’s functions.php file:

// popular posts per category
function popular_posts_per_category() {
	global $post;
	$categories = get_the_category();
	foreach($categories as $category) {
		$cats[] = $category->cat_ID;
	}
	$cats_unique = array_unique($cats);
	$args = array(
		'category__in' => $cats_unique,
		'orderby' => 'comment_count',
		'order' => 'DESC',
		'post_type' => 'post',
		'post_status' => 'publish',
		'posts_per_page' => 5
	);
	echo '<ul>';
	$popular_posts = null;
	$popular_posts = new WP_Query($args);
	while ($popular_posts->have_posts()) : $popular_posts->the_post(); 
		$title_trim = get_the_title();
		if (strlen($title_trim) > 60) {
			$title_trim = substr($title_trim,0,60);
		} ?>

		<li><a href="<?php the_permalink(); ?>"><?php echo $title_trim; ?></a></li>
	<?php endwhile;
	rewind_posts();
	echo '</ul>';
}

..and then display the list wherever in your theme using this template tag:

<?php popular_posts_per_category(); ?>

There’s a lot going on in the code above, so here’s the scoop if you’re into understanding what you’re doing:

  1. First we create an array of unique categories
  2. Then we set up our arguments for the new WP_Query()
  3. Finally the results are truncated and displayed as a nice list

Note there are several ways to customize this technique. You can customize the query itself, for example, to get more popular posts by editing the posts_per_page parameter. Another good thing to customize is the substr() action that shortens the length of the post title — super-useful when displaying the popular-post list in smallish places.

And lastly, you can use additional parameters to further refine the popular-post query. For example, I want to exclude posts from certain tags from appearing on the list, so I include the following argument in the array:

'tag__not_in' => array(38,81,390),

..where 38, 81, and 390 are IDs of the tags I want to omit. WordPress provides a cornucopia of other parameters to help with further fine-tuning of your custom queries.

Allow markup in category descriptions

This next trick does one thing and does it well: allows markup in your category descriptions. By default, HTML markup is stripped from category descriptions, but thanks to this thread, the following code makes it possible:

// markup in category descriptions
$filters = array('pre_term_description', 'pre_link_description', 'pre_link_notes', 'pre_user_description');
foreach ($filters as $filter) {
	remove_filter($filter, 'wp_filter_kses');
}

Bada-boom, bada-bing — no editing required, just drop into your functions.php file and you’re good to go.

Add extra fields to category meta

Lastly, we have a technique for adding an extra fields to the category metadata. In my case, I wanted to include category meta boxes for a custom title and a category thumbnail image. After some searching and fiddling, I found this method works a treat for making it happen. Add the following code to your functions.php file:

// add extra fields to category meta
define('MY_CATEGORY_FIELDS', 'my_category_fields_option');
add_filter('edit_category_form', 'my_category_fields');
function my_category_fields($tag) {
	$tag_extra_fields = get_option(MY_CATEGORY_FIELDS); ?>
	<table class="form-table">
		<tr class="form-field">
			<th scope="row" valign="top"><label for="custom_cat_title">Custom Category Title</label></th>
			<td><textarea  name="custom_cat_title" id="custom_cat_title"><?php echo $tag_extra_fields[$tag->term_id]['my_description']; ?></textarea>
				<p class="description">Custom category title attribute for menus on parent pages</p></td>
		</tr>
		<tr>
			<th scope="row" valign="top"><label for="custom_cat_thumb">Custom Category Thumbnail</label></th>
			<td><input name="custom_cat_thumb" type="text" id="custom_cat_thumb" size="50" aria-required="false" value="<?php echo $tag_extra_fields[$tag->term_id]['my_thumbnail']; ?>" />
				<p class="description">Upload the image and enter the filename here.</p></td>
		</tr>
	</table>
    <?php
}
add_filter('edited_terms', 'update_my_category_fields');
function update_my_category_fields($term_id) {
  if($_POST['taxonomy'] == 'category'):
    $tag_extra_fields = get_option(MY_CATEGORY_FIELDS);
    $tag_extra_fields[$term_id]['my_description'] = strip_tags($_POST['custom_cat_title']);
    $tag_extra_fields[$term_id]['my_thumbnail'] = strip_tags($_POST['custom_cat_thumb']);
    update_option(MY_CATEGORY_FIELDS, $tag_extra_fields);
  endif;
}
add_filter('deleted_term_taxonomy', 'remove_my_category_fields');
function remove_my_category_fields($term_id) {
  if($_POST['taxonomy'] == 'category'):
    $tag_extra_fields = get_option(MY_CATEGORY_FIELDS);
    unset($tag_extra_fields[$term_id]);
    update_option(MY_CATEGORY_FIELDS, $tag_extra_fields);
  endif;
}

Once added to your functions file, this code will generate two custom meta fields in the Edit Category page in the WP Admin. The first field is for a custom title, and the second is for a custom category image. No editing is required to make this work, but the application is rather project-specific, so you’ll probably want to customize things by adding/removing fields, modifying markup, and so on to suit your specific needs.

Wrap up

Categories arguably are the primary vehicle for content organization. Yet sadly, most sites do very little to emphasize and promote their best content in ways that are contextually relevant and easy to navigate. In this post, I outline some effective ways to maximize your WordPress category archives using a variety of choice, custom-crafted code snippets. No more excuses for boring category archives people!

About the Author
Jeff Starr = Web Developer. Book Author. Secretly Important.
WP Themes In Depth: Build and sell awesome WordPress themes.

14 responses to “Category Functions for WordPress”

  1. Artful Dodger 2012/04/12 9:50 am

    I’m currently working on a custom WordPress theme and this contains exactly what I’m looking for.

    HOW DID YOU KNOW?

  2. While I ended up opting for something slightly different in regards to category icons (settled on using a background image applied to the category-name classes — basically a css only solution) this is an awesome post.

    If only I had found this a couple days ago… Oh well, still bookmarked :)!

  3. Lionel Pointet 2012/04/16 4:32 am

    Some exciting snippets here, great job!

    I just noted a few things in your “Display sub-categories of current category” code :

    1. Don’t write $category->slug directly in the URL, or only if you know what’s going on with your installation and permalinks. Instead, you should have written get_category_link($category->term_id)

    2. If you just need to display the list of sub-categories if it exists, you can use wp_list_categories, which accepts the same parameters

  4. Wow, that’s pretty awesome for me. WP so deep. Thanks you so much for sharing this!

  5. Just wanted to say thanks! for the great category image fix. Worked perfectly!

  6. Hey .. just wanted to say thanks for the category functions for wordpress post. Saved my day!!

  7. Jeff Starr 2012/06/26 6:48 pm

    Thanks everyone for the great feedback! It’s my pleasure to share :)

  8. David Stembridge 2012/08/06 4:17 pm

    Hi Jeff, great tutorial! do you mind elaborating on using body class to trigger a 3 column layout on a WP theme that gives you multiple layout possibilities? (Nom Nom) I selected the 2 column layout; but want to filter the 3 column layout for the front page.

  9. Hi,

    Excellent and useful information! I’m very interested by the “Popular posts per category” section.

    I have several questions:

    1. The visitor has to be on the category page or it will work on a single post page > if I’m reading your “category functions WP” post that is under the category “wordpress”, I will have to popular post from that category? or i need t be on the “wordpress” category page?
    2. If I want the latest posts instead of the popular ones how to I do that?
    3. To tweak it to the extreme, If I want the latest post from a specific post type (CPT)? I guess I will only have to change 'post_type' => 'post' to 'post_type' => 'CPT-name'

    That’s reallt interesting to be able to present the exact information we think will be useful for the visitor in a dynamic way (not having to specify the category ID manually in the code but retrieving it from the post itself instead)

  10. Hi Again,

    I found the answers to my questions myself by trying and testing…

    1. that works on single posts
    2. I renamed the function recent_post_by_category and changed the orderby with post_date. And of course,I’ve changed the template tag to insert.
    3. changing post type works perfectly too.

    Thanks again for sharing it!

  11. Love the site and particularly this post! I have a question about displaying sub-categories of current category. When I put the code in and call the function in page.php, it ALL of the categories are listed, not simply the sub-categories. I am mapping categories to pages using plugin here could this be the problem?

    • Jeff Starr 2013/01/16 2:58 pm

      Hi Tracy, yes it could be causing an issue.. I would try disabling the plugin temporarily and see if that helps.

  12. This is great. For the “Add extra fields to category meta” – once the additional category meta has been added, how do you then display the custom title in the theme?

    Many thanks
    Dave

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
.htaccess made easy: Improve site performance and security.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.