Last updated June 22nd, 2024 at 06:34 pm
Use Case for Adding Taxonomies to the WordPress Body Class
Sometimes it’s desirable to render WordPress posts or pages distinctively based on the categories or tags assigned to them. (Spoiler alert: leverage the body class property.)
For example, suppose your WordPress blog consists of articles that are categorized as either Documentation or Ramblings. The Documentation category is for formal, structured articles that explain processes and procedures. The Ramblings category is for informal articles through which you share — well, ramblings — that cover lots of different topics.
Further suppose that you want to display your Documentation posts in a formal way and your Ramblings posts in an informal way.
You’ve decided that the way to do this is to use a formal serif font for Documentation and an informal handwriting font — as well as a background image that looks like lined notebook paper — for Ramblings.

How would you accomplish this?
Categories/Tags to the Rescue
One way is to add category and tag classes to the body element and to write rules with appropriate selectors.
“But doesn’t WordPress already do this?” you ask.
Sort of.
While many WordPress themes automatically add the category and tag identifiers to the article element, they do not (by default) add such identifiers to the body element. The reason this matters is that some of the HTML elements you want to render differently (based on the post’s categories or tags) are outside of the article element. (The body element — which you’d most likely want to target for the lined notebook paper background image — is such an element.)
So, the trick is simply to add category and tag identifiers to the body element. And this is pretty easy to do for blog posts, since categories and post_tags are enabled for blog posts by default.
Here’s how:
PHP Script to add post category to body class list:
function nwb_add_category_to_single_action() {
add_filter('body_class','nwb_add_category_to_single');
function nwb_add_category_to_single($classes) {
if (is_single() || is_page() ) {
global $post;
foreach((get_the_category($post->ID)) as $category) {
// Add category slug to the $classes array
$classes[] = $category->category_nicename;
}
}
// Return the $classes array
return $classes;
}
}
add_action('after_setup_theme', 'nwb_add_category_to_single_action');
Now, every post categoried as Documentation will have a body class of documentation, and every post categorized as Ramblings will have a body class of ramblings.
All that’s left to do is add CSS rules that create your desired effects. Examples:
CSS targeting body class:
body.ramblings {
background-image: url(/images/lined-paper.png);
background-repeat: repeat-y;
font-family: "Comic Sans" cursive;
}
body.documentation {
font-family: "Times New Roman", Times, Georgia, serif;
}
Does this Body Class solution work for Pages?
Actually, the script above does address pages (see line 4, where the condition says, “If this is a single post or a page, then…”).
However, WordPress does not (for whatever reason) enable categories or tags for pages by default. The good news is that you can do that easily. Add these lines of code, using the WordPress register_taxonomy_for_object_type function, to your child theme’s functions.php (or, as I prefer, to a file in your mu-plugins folder):
PHP Script to enable categories and tags for Pages:
function nwb_add_taxonomies_to_pages() {
register_taxonomy_for_object_type( 'post_tag', 'page' );
register_taxonomy_for_object_type( 'category', 'page' );
}
add_action( 'init', 'nwb_add_taxonomies_to_pages' );
What about Custom Post Types?
The process is very similar for custom post types, with a few minor exceptions. This example uses the MembersPress Lesson post type (mpcs-lesson and is documented more fully here.
First, you need to make sure that the mpcs-lesson post type supports tags. And since I’m creating a new taxonomy for Lessons (i.e., I don’t want to use the categories and post_tags that “come with” WordPress posts), I need to do a little more work.
PHP Script to enable tags for Custom Post Types:
Register the custom taxonomy (in this case, lesson_tags) like so:
add_action( 'init', 'fto_tax_lesson_tags', 0 );
function fto_tax_lesson_tags() {
$labels = array(
'name' => 'Lesson Tags',
'singular_name' => 'Lesson Tag',
'menu_name' => 'Lesson Tags',
'all_items' => 'All Lesson Tags',
'parent_item' => 'Parent Item',
'parent_item_colon' => 'Parent Item:',
'new_item_name' => 'New Lesson Tag',
'add_new_item' => 'Add New Lesson Tag',
'edit_item' => 'Edit Lesson Tag',
'update_item' => 'Update Lesson Tag',
'view_item' => 'View Lesson Tag',
'separate_items_with_commas' => 'Separate items with commas',
'add_or_remove_items' => 'Add or remove Lesson Tags',
'choose_from_most_used' => 'Choose from the most used',
'popular_items' => 'Popular Lesson Tags',
'search_items' => 'Search Lesson Tag',
'not_found' => 'Not Found',
'no_terms' => 'No items',
'items_list' => 'Lesson Tags list',
'items_list_navigation' => 'Lesson Tags list navigation',
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
);
register_taxonomy( 'lesson_tags', array( 'mpcs-lesson' ), $args );
}
Line 35 associates the new taxonomy (lesson_tags) with the mpcs-lesson post type.
Now add the code for appending classes for lessons to lesson pages:
add_action('after_setup_theme', 'nwb_add_tax_to_single_action');
function nwb_add_tax_to_single_action($classes) {
add_filter('body_class','nwb_add_tax_to_single');
function nwb_add_tax_to_single($classes) {
$this_post_type = get_post_type(get_the_ID());
$post_type_cos = 'this-post-type_' . $this_post_type;
if ( is_singular('mpcs-lesson') ) {
global $post;
$taxonomy_terms = get_the_terms($post->ID, 'lesson_tags');
if ( $taxonomy_terms ) {
foreach((get_the_terms($post->ID, 'lesson_tags')) as $term) {
// *** Add category slug to the $classes array
$classes[] = 'lesson-tag-' . $term->slug;
}
}
$classes[] = $post_type_cos;
// *** return the $classes array
return $classes;
}
}
}
Assuming I assigned the lesson_tag “video” to one of the lessons, the body element would look something like this (I’m omitting all of the classes that WordPress and MemberPress add, for clarity):
<body class="lesson-tag-video this-post-type_mpcs-lesson">
The lesson-tag-video comes from line 13; the this-post-type_mpcs-lesson, which represents the post type, comes from lines 6 and 16.
Remember Post Formats?
Post Formats were introduced in WordPress version 3.1. Initially at least, this feature performed essentially the same function as the snippets above: Namely, it allowed you to distinctively format posts based on one of the preset post formats defined by WordPress. These post formats are kinda-like categories or tags. Those preset formats — as of this writing — are (and I’ve copied from the above-referenced WordPress dot org page):
- aside: Typically styled without a title. Similar to a Facebook note update.
- gallery: A gallery of images. Post will likely contain a gallery shortcode and will have image attachments.
- link: A link to another site. Themes may wish to use the first
<a href="">tag in the post content as the external link for that post. An alternative approach could be if the post consists only of a URL, then that will be the URL and the title (post_title) will be the name attached to the anchor for it. - image: A single image. The first
<img>tag in the post could be considered the image. Alternatively, if the post consists only of a URL, that will be the image URL and the title of the post (post_title) will be the title attribute for the image. - quote: A quotation. Probably will contain a blockquote holding the quote content. Alternatively, the quote may be just the content, with the source/author being the title.
- status: A short status update, similar to a Twitter status update.
- video: A single video or video playlist. The first
<video>tag or object/embed in the post content could be considered the video. Alternatively, if the post consists only of a URL, that will be the video URL. May also contain the video as an attachment to the post, if video support is enabled on the blog (like via a plugin). - audio: An audio file or playlist. Could be used for Podcasting.
- chat: A chat transcript, like so:
Some of the formatting was accomplished by the WordPress “engine”; for example, the entry title of a post assigned the link post format would be converted to a clickable link. Much of the formatting, however, was accomplished through CSS. An appropriate class name (e.g., single-format-aside, single-format-gallery, single-format-link, etc.) is appended to the body element’s class property for targeting with CSS.
Here’s a sampling of CSS rules in the Twentyeleven style sheet (it’s long; click to expand):
/* =Aside
----------------------------------------------- */
.format-aside .entry-title,
.format-aside .entry-header .comments-link {
display: none;
}
.singular .format-aside .entry-title {
display: block;
}
.format-aside .entry-content {
padding: 0;
}
.singular .format-aside .entry-content {
padding: 1.625em 0 0;
}
/* =Link
----------------------------------------------- */
.format-link .entry-title,
.format-link .entry-header .comments-link {
display: none;
}
.singular .format-link .entry-title {
display: block;
}
.format-link .entry-content {
padding: 0;
}
.singular .format-link .entry-content {
padding: 1.625em 0 0;
}
/* =Gallery
----------------------------------------------- */
.format-gallery .gallery-thumb {
float: left;
display: block;
margin: .375em 1.625em 0 0;
}
/* =Status
----------------------------------------------- */
.format-status .entry-title,
.format-status .entry-header .comments-link {
display: none;
}
.singular .format-status .entry-title {
display: block;
}
.format-status .entry-content {
padding: 0;
}
.singular .format-status .entry-content {
padding: 1.625em 0 0;
}
.format-status img.avatar {
-moz-border-radius: 3px;
border-radius: 3px;
-webkit-box-shadow: 0 1px 2px #ccc;
-moz-box-shadow: 0 1px 2px #ccc;
box-shadow: 0 1px 2px #ccc;
float: left;
margin: 4px 10px 2px 0;
padding: 0;
}
/* =Quote
----------------------------------------------- */
.format-quote blockquote {
color: #555;
font-size: 17px;
margin: 0;
}
/* =Image
----------------------------------------------- */
.indexed.format-image .entry-header {
min-height: 61px; /* Prevent the comment icon from colliding with the image when there is no title */
}
.indexed.format-image .entry-content {
padding-top: 0.5em;
}
.indexed.format-image .entry-content p {
margin: 1em 0;
}
.indexed.format-image .entry-content p:first-child,
.indexed.format-image .entry-content p:first-child a,
.indexed.format-image .entry-content p:first-child img {
display: block;
margin: 0;
}
.indexed.format-image .entry-content .wp-caption .wp-caption-text {
margin: 0;
padding-bottom: 1em;
}
.indexed.format-image footer.entry-meta {
background: #ddd;
overflow: hidden;
padding: 4%;
max-width: 96%;
}
.indexed.format-image div.entry-meta {
display: inline-block;
float: left;
width: 35%;
}
.indexed.format-image div.entry-meta + div.entry-meta {
float: none;
width: 65%;
}
.indexed.format-image .entry-meta span.cat-links,
.indexed.format-image .entry-meta span.tag-links,
.indexed.format-image .entry-meta span.comments-link {
display: block;
}
.indexed.format-image footer.entry-meta a {
color: #444;
}
.indexed.format-image footer.entry-meta a:hover {
color: #fff;
}
#content .indexed.format-image img {
border: none;
max-width: 100%;
padding: 0;
}
.indexed.format-image .wp-caption {
background: #111;
margin-bottom: 0;
max-width: 96%;
padding: 2% 2% 0;
}
.indexed.format-image .wp-caption .wp-caption-text {
color: #ddd;
}
.indexed.format-image .wp-caption .wp-caption-text:before {
color: #444;
}
.indexed.format-image a:hover img {
opacity: 0.8;
}
Which is better?
It’s not an either/or thing. Post formats have their place, and I experimented with them when they first came out. Frankly, though, I can’t remember the last time I used them. Conversely, I often use this “trick” of adding category and tag slugs to the body element (use case here) in order to distinctively style page elements.
Comments Welcome
Did this post help in any way? Do you have a better way to accomplish the same end? Do you use post formats? Questions about the code? Let me know what you think.
Like what you see? Share with others and join my mailing list. No long-term commitment, unsubscribe any time.

Leave a Reply