WordPress 2.8 and the body_class() Function

Back on February 7th, I was casually browsing the WordPress trunk code, and discovered a very cool new function in the wp-includes/post-template.php file.

Beginning in WordPress 2.8, themes will be able to take advantage of the body_class() function to place location-specific classes on the opening <body> tag, usually located in the header.php file of most themes.

Why is this significant? Easy … this opens up the ability to change the look of nearly everything with CSS only.

Before we get into the application of the body_class() function, let’s cover some technical details first.

What body_class() Generates

The body_class() function operates in nearly the exact same manner as the post_class() function that was introduced in WordPress 2.7. The only differences are the classes it generates. The body_class() function will generate the classes mostly based on where your viewer is on your site.  For instance, if a viewer is on your homepage and you haven’t set a static page for your homepage, then the classes the function might generate might look like this:

<body class="home blog">

Notice, those are two separate classes, either of which you can use as a selector.

However, if you are on a particular post, the body tag might look like this:

<body class="single postid-64">

And if you are currently looking at a page, then body_class() will generate something like this:

<body class="page page-id-3 parent-page-id-0 page-template-default">

Essentially, body_class() will generate dynamic CSS classes based on the type of content, and under what circumstances, you are currently browsing. For instance, if you are a registered user, and are currently logged in, body_class() will generate a logged-in class on the body tag.

The following is a full list of possible body classes (HT: WPEngineer.com):

  • rtl
  • home
  • blog
  • archive
  • date
  • search
  • paged
  • attachment
  • error404
  • single postid-(id)
  • attachmentid-(id)
  • attachment-(mime-type)
  • author
  • author-(user_nicename)
  • category
  • category-(slug)
  • tag
  • tag-(slug)
  • page
  • page-parent
  • page-child parent-pageid-(id)
  • page-template page-template-(template file name)
  • search-results
  • search-no-results
  • logged-in
  • paged-(page number)
  • single-paged-(page number)
  • page-paged-(page number)
  • category-paged-(page number)
  • tag-paged-(page number)
  • date-paged-(page number)
  • author-paged-(page number)
  • search-paged-(page number)

How To Add body_class() to My Theme

This is actually the easy part. Assuming you are running WordPress 2.8 (currently in beta, soon to be released), all you have to do is add a new template tag. You’ll need to locate which template file generates the opening <body> tag. This is usually the header.php file.

After you’ve located the <body> tag, just change it to this:

<body <?php body_class(); ?>>

Save the file (and upload to your server, if necessary), and you’re done!

Using Dynamic Body Classes

So, we now have body classes. What’s the big deal? I’ll explain:

With the exception of the HTML element, the <body> tag wraps around all other HTML code. Therefore, by having classes on <body> allows us to target any other element on the page, specific to the current <body> class.

It may just be easier to explain by example.

Let’s say that I have a <div id="content"> that renders on the left, and a <div id="sidebar"> that renders on the right, both within a 960px wide <div id="container">. The content div is 600px wide, and the sidebar is 360px wide. But, when viewing a single post (as opposed to the homepage), I have told my theme to not display the sidebar. Now, we’re left with just a content column. Unfortunately, our container is 960px wide, and our content div is only 600px wide.

We’re stuck with a large blank space where the sidebar used to be. How do we fix that? With a <body> class, it’s easy. We just target the <div id="content"> when it is being displayed on a single post. It would looks something like this in CSS:

.single #content {
	width: 960px;
}

By doing this, we’re saying “if we’re viewing a single post, make the #content div 960px wide”.

We’re basically adding a simple conditional system to CSS.

Adding Classes to body_class()

In some cases, you will want to add your own class(es) to the list of classes that body_class() generates. If you find yourself in this situation, here are a couple of ways to do it.

The first, and easiest, way to add a class to the list of classes the function generates is to simply pass your custom class as a function argument to body_class(). Here’s how you would do that:

<body <?php body_class('my-class'); ?>>

By doing this, we’ve now told the body_class() function to add ‘my-class’ to the list of classes to output.

The second, and harder (but more flexible) way is to use take advantage of a WordPress Filter to add new body class(es). In this case, we’ll be using the body_class filter provided in the get_body_class() function. If you don’t understand how filters work, I’ll do a post on that in the future. Until then, see if you can just follow along. You may pick it up pretty easily.

Here’s an example of how to add a class by using a filter:

<?php
add_filter('body_class','my_body_classes');
function my_body_classes($classes, $class) {
	// add 'my-class' to the $classes array
	$classes[] = 'my-class';
	// return the $classes array
	return $classes;
}
?>

By using this method, we allow ourselves to use conditionals, and other cool things, that we would not be able to use with the first method.

Further Reading

If you want to know more about the body_class() function, here are a few resources I’d recommend:

Comments

  1. says

    This is a feature I’ve been waiting for. This is really going to help me style sites where users can login in and view things differently.

  2. says

    This can also be done with PHP constants (the define() function). I’ve been using that, but body_class() will negate the need for it now. :)

  3. says

    Yay it finally arrives. Wanted this function badly for my employer last year, I had to do it drupal way I am familiar with. Now that it’s here I should no longer worry. More and more powerful indeed.

  4. curt gideon says

    downloaded 2.8 and i can’t get my thumbnails to insert anymore, also when i approve a note, it doesn’t show anymore….. any advise…….. thanks

  5. mpmchugh says

    Is it possible, perhaps via a filter to add the category slug(s) for a single post as a class to the body_class function output?

    Or is there something that can be coded right in the body_class() function call?

    Thanks,
    Michael

  6. Chris says

    Hi there… I really enjoyed the post and have had fun using the body_class() function–successfully–for the ‘home’, ‘single’ and ‘page’ classes. However, I’m trying to figure out how to use the function with “specific WP pages” and for some reason I can’t figure it out. In other words, how can I set up a body class that applies only to particular WP page (e.g. page ID 19)? Any help you can offer would be much appreciated. Thanks.

    Best, Chris

    • says

      It will output classes based on page IDs. For instance, on my About page, this is the body_class() output:

      
      <body class="page page-id-3 page-template page-template-default">
      

      Notice the page-id-3 class? That means that we’re viewing a page with an ID of 3. Use that to style specifically to target that page.

  7. mpmchugh says

    Still looking for help with getting the ‘category-slug’ to be added to the body_class function output.

    All it seems to output by default for single posts is: <body class="single postid-309">

    Thanks,
    Michael

  8. Chris says

    Thanks for getting back to me so quickly… I really appreciate it. Well, I thought I understood your reply, and tried implementing your suggestions (several different ways). Sadly, I still can’t figure it out. Any chance you want to try and walk me through it one more time? If so, here’s some details.

    Here’s the URL that I’m working on:

    http://www.thomas-holden.com

    Here’s the code that I have placed in the header file:

    <body >

    Here’s the CSS that I’ve been working with:

    .single #logo {
    background: #ffffff url(images/blog_header.jpg) no-repeat;
    }

    .home #logo {
    background: #ffffff url(images/blog_header.jpg) no-repeat;
    }

    .page #logo {
    background: #ffffff url(images/teaching_header.jpg) no-repeat;
    }

    .page page-id-19 page-template page-template-default #logo {
    background: #ffffff url(images/cv_header.jpg) no-repeat;
    }

    If you click on some of the navigation, you’ll see that the background image for the #logo div changes. Everything except for the page specific (i.e. page-id-19) styling is working fine. Where did I go wrong? Thanks again for your help.

  9. Chris says

    Please forget my last post… I’m an idiot and just figured out what my problem was. Thanks.

  10. Bill says

    Hi, this only shows the parent one level up. On a page a few levels down in the navigation, there’s no way to tell what the top level ancestor id is, sadly.

    For example, consider

    Top
    Sub
    SubSub

    If you;re on SubSub, it would be nice to have a class of the “Top” page ID, since it is an ancestor. But, the included WP functionality won’t do it. It will show you Sub’s page ID.

  11. says

    Oh my word! I’ve been building WordPress sites with my own kludged together get_body_class function for the last year or so.

    This evening I decided to try moving my function into functions.php, but this was breaking WordPress. I searched all the source code and a broad grin broke across my face when I discovered the ‘official’ get_body_class function – that’s how I found this blog post and that’s why I wanted to say thanks, to you and to WordPress.

    I’m still grinning :D

  12. says

    Wow, your example solves the EXACT problem I had : I don’t show the sidebar on the homepage, and wanted to let the main contents occupy the whole width, so thanks mate!

    bookmarked and tagged

  13. Adam says

    I’m trying to style a specific page link only when I’m actively on that page.

    What do I output in my body class if my page id ‘about’ has a class of ‘page-item-6′ and it’s php template file is about.php.

  14. says

    hello, all:

    i’m confused about leveraging the body class in 2.8. i believe you’re saying that in 2.8 we do not have to copy/paste the following in the header.php because it’s already there, yeah?

    let’s say i have a page called about, and my blog page is called news.

    if i want to change the body bg color (using Kubrick theme) on either of these pages, how would i go about doing so? Why can’t i simply put the following into my css:

    body.about {background: orange;}
    or
    body.news {background: red;}

    i’ve had success with following (.page {background: green;}, but need more granular control, because both the News and About are equally effected by that snippet of css. And i need those 2 pages to have different bg colors.

    thanks!

  15. mika says

    Hi,

    i’m using the following code :

    body.category-title1 #page-top { background: url("images/page_top1.jpg") no-repeat; }
    body.category-title2 #page-top { background: url("images/page_top2.jpg") no-repeat; }
    body.category-title3 #page-top { background: url("images/page_top3.jpg") no-repeat; }
    body.category-title4 #page-top { background: url("images/page_top4.jpg") no-repeat; }
    body.category-title5 #page-top { background: url("images/page_top5.jpg") no-repeat; }</code

    The result is one header for each category of my blog. However, it doesn't work for the posts of my categories (it works only on the category pages).

    Any idea, please ?

  16. says

    The tip on how to use wordpress filters to add new body classes is money! Never thought about doing that, tedious but your right! Much more flexible.

    Thanks