Ultimate WordPress body_class()

Good themes for WordPress make use of two fundamental functions to help you style posts and pages contextually, the body_class() function, and the similar post_class() function.

However, there is the risk to overlap classes among the body element and the post container.

Duplicated classes

The post_class() function adds to the post container the categories to which the post is assigned to. Assuming we are opening the archive page for the category Review, we will have something similar to the markup below.

<body class="archive category category-review category-13">
<!-- ...and few lines later... -->
<article id="post-139" class="post-139 post type-post status-publish format-standard hentry category-review post-body">
...
</article></body>

If you pay attention, the class category-review has been assigned to both the body element and the post container.

Duplicated classes in your markup, especially in elements within one another, force you to increase specificity in your CSS.

body.category-review { /* contextual styling */ }  
article.category-review { /* contextual styling */ }  

Sure you can live with it. But I do prefer to keep specificity as low as possible.

The Ultimate body_class filter

After few tests I ended up with a solution I’m quite happy about. The function below can be placed in the functions.php file. What it does is filtering the default body_class() function.

if ( ! function_exists('my_body_class')) {
add_filter('body_class','my_body_class');
function my_body_class($classes) {
  global $wp_query, $post;
  if ( is_front_page()) { $classes[] = 'front-page'; }
  if ( is_page()) { $classes[] = 'page-'.$wp_query->query_vars['pagename']; }
  if ( is_singular()) { $classes[] = 'slug-'.$post->post_name; }
  if ( is_singular()) { $classes[] = 'post-type-'.$post->post_type; }
  if ( !is_404() && get_the_category( $post->ID)) {
    foreach (( get_the_category($post->ID)) as $category) {
      $classes[] = 'body-category-'.$category->category_nicename;
    }
  }
  return $classes;
}}

The filter make sure that the body element still has a class relative to an eventual category page, but also it avoids overlaps with classes assigned to the post container.

But now it will not be simply category-review, but body-category-review.

You can also change the line:

$classes[] = ‘body-category-‘.$category->category_nicename;  

In something that better works for you.

How to use it?

Assuming the theme does not have already a similar feature, a quick way to apply your new body_class() filter is to copy and past the code above directly into the functions.php file of your theme.

The files of a theme are usually located in the folder wp-content/themes/name-of-your-theme/

And the file functions.php is placed in the root of the theme.

If there is not such a file you can create it.

Pay attention to respect the PHP syntax, so that everything into the file is correctly encased within <?php and ?>.