List WordPress Categories With an Active Class

A list of WordPress categories with an active class is the usual filter menu above a blog or portfolio: every category as a link, and the one you are looking at highlighted with current-cat.

This shortcode prints that list for categories or any custom taxonomy. On a category archive the current category is marked, and on a single post the post’s own categories are, which plain wp_list_categories() does not do.

  • [dpc_term_list] lists the post categories.
  • [dpc_term_list taxonomy="produkte"] lists a custom taxonomy.
  • [dpc_term_list hide_empty="no" orderby="count"] also shows empty terms, ordered by post count.

The snippet

<?php
/**
 * [dpc_term_list taxonomy="category"]
 * All terms of a taxonomy as links; the current one gets the current-cat class.
 */
add_shortcode( 'dpc_term_list', 'dpc_term_list_shortcode' );

function dpc_term_list_shortcode( $atts ): string {
	$atts = shortcode_atts(
		array(
			'taxonomy'   => 'category',
			'hide_empty' => 'yes',
			'orderby'    => 'name',
		),
		$atts,
		'dpc_term_list'
	);

	$taxonomy = sanitize_key( $atts['taxonomy'] );
	if ( ! taxonomy_exists( $taxonomy ) ) {
		return '';
	}

	$args = array(
		'taxonomy'         => $taxonomy,
		'orderby'          => in_array( $atts['orderby'], array( 'name', 'count', 'term_order', 'id' ), true ) ? $atts['orderby'] : 'name',
		'hide_empty'       => ! in_array( strtolower( (string) $atts['hide_empty'] ), array( 'no', 'false', '0', 'off' ), true ),
		'title_li'         => '',
		'show_option_none' => '',
		'echo'             => false,
	);

	// On archives WordPress marks the current term itself; on a single post mark the post's terms.
	if ( is_singular() ) {
		$post_terms = wp_get_post_terms( get_queried_object_id(), $taxonomy, array( 'fields' => 'ids' ) );
		if ( $post_terms && ! is_wp_error( $post_terms ) ) {
			$args['current_category'] = $post_terms;
		}
	}

	$items = wp_list_categories( $args );

	return $items ? '<ul class="dpc-term-list dpc-term-list--' . esc_attr( $taxonomy ) . '">' . $items . '</ul>' : '';
}

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor and publish. Leave Action/Hook empty.

Then use [dpc_term_list] anywhere shortcodes run: post content, a Shortcode block in a block theme template, a widget or your page builder’s shortcode element. This is a normal shortcode rather than a Shortcode location block because it takes a taxonomy attribute: one code block serves your categories and every custom taxonomy, and it is registered for the block editor’s preview too.

The same code also works unchanged in a small plugin or an mu-plugin.

How it works

  • wp_list_categories() builds the li items for any taxonomy, with cat-item classes and current-cat plus aria-current="page" on the current term of a category, tag or taxonomy archive.
  • On single posts it has no current term, so the shortcode passes the post’s term IDs in current_category, which accepts several IDs.
  • title_li and show_option_none are empty, so you get only the items: no “Categories” heading and no “No categories” item. The ul is only printed when there is at least one term.
  • The taxonomy goes through sanitize_key() and taxonomy_exists(), orderby through a short allowlist, hide_empty accepts no, false, 0 or off, and WordPress escapes the term names and links.

Customise it

  • Style the active item: .dpc-term-list .current-cat>a{font-weight:700}.
  • Highlight the parent of the current category too: WordPress adds current-cat-parent and current-cat-ancestor; add 'depth' => 0 to $args to show the hierarchy.
  • Just a few terms as inline links, with a limit: see Output taxonomy terms as links with limit.

Gotchas

  • Empty terms are hidden by default, and only published posts count, so a category with only drafts does not show.
  • Block themes have a Terms List (Categories List) block; it does not mark the current post’s categories, which is the main reason for this snippet.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.