FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Home  »  WordPress  »  Add CSS Class to body when Sidebar is Present

by 2 comments

Here's the problem I was having while working on a custom theme for a client. Certain pages, posts, tag pages, archive pages, and custom pages either had the sidebar, or did not have the sidebar. The main content div #ContentW had a 72% width when the sidebar was present, otherwise it was 96%. The problem was that I dislike having to do things manually when they can be automated through code. What I was having to do was manually add/remove page-specific classes to the css file to reflect whether the sidebar was present on that page or not.

body_class()

WordPress uses a function called body_class() to output page-specific classnames for the <body class=""> tag. So for instance on a single post, body_class includes the class "single" along with others like "post-147" or "page-123" or "category-34" depending on what page it is.

So back to my width problem: I was having to create css rules for each specific type of page to be applied to the ContentW div to make it either wide (no sidebar) or not.. The following css is for pages that have the sidebar, thus making the #ContentW div only 72% wide. These include the homepage, single post pages, and a page with the id of 345.

.home #ContentW,
.single #ContentW,
.page-345 #ContentW { width:72%; }

What I really would like to do would be to just add a class to body named "withsidebar" that is automatically added to the body class when sidebar.php is included, and is automatically not added when sidebar.php is not included. Then my css would be so simple:

#ContentW { float:left; overflow:hidden; width:96%; }
.withsidebar #ContentW { width:72%; }

Meaning I'm free to include or not include the sidebar on any page or post on the site and the #ContentW width will always be right.

In the header

The problem, is that body_class() is executed in the themes header.php file by the get_header() function, which is always called before calling get_sidebar() to include sidebar.php, SO I wasn't able to change the output of body_class() to reflect whether or not sidebar.php had been included or not. By the time sidebar.php was included, body_class had already been output.

The Solution for adding a sidebar class

The solution I came up with is very nice and foolproof, and is only 2 lines of code. Simply does a basic "search and replace" on the output of get_header, where body_class is executed to replace or remove my own class to the body tag when the sidebar is included.

<?php
add_action('wp_head',create_function("",'ob_start();'));
add_action( 'get_sidebar', create_function('','echo str_replace("<body class="","<body class="withsidebar ",ob_get_clean());ob_start();') );
?>

Start output buffer in header

First I started an output buffer with ob_start() (to save the output of get_header) by hooking into the wp_head action which is where body_class is executed.

add_action('wp_head',create_function("",'ob_start();'));

I prefer to use create_function when possible, but the above is exactly the same as:

add_action('wp_head','start_sidebar_class_fix_output');
function start_sidebar_class_fix_output()
{
  ob_start();
}

Search and Replace Function in sidebar.php

Now that the output from wp_header containing the body class is accessible in an output buffer, we need to be able to execute the search and replace ONLY when the sidebar.php file is included. To do this, I hooked into the get_sidebar action that is called by get_sidebar(). This function created by create_function replaces <body class=" with <body class="withsidebar in the $buffer and echos it. If the search string isn't found it echos the $buffer intact.

add_action( 'get_sidebar', create_function('','echo str_replace("<body class="","<body class="withsidebar ",ob_get_clean());ob_start();') );

This function simply adds "withsidebar" to the body class by search and replace on the output buffer. The output buffer passed to the str_replace function by using ob_get_clean() which returns the buffer. Finally, ob_start is called again to resume output buffering (it will automatically be flushed at EOF), just because I like doing things that way, it's not neccessary to restart the output buffer with ob_start however.

Enhanced for Multiple Sidebars

Now then, say you have multiple sidebars like sidebar-left.php and sidebar-right.php, and you want a class added to the body class for every single sidebar that is used? Or let's decide we want this sidebar class adding-feature as robust and future-proofed as needed (in case you use multiple sidebars or your theme does in the future).

Instead of the code above, use this. Just paste it into your themes functions.php file or add it to a plugin (paste this in the file /wp-content/plugins/sidebar_class_replace.php and you have yourself a plugin).

This enhanced version still adds the class "withsidebar" to the body class the first time any sidebar is included. Every additionaly sidebar that is included has a class appended to the body class as well. Finally, in the wp_footer the search and replace takes place, 1 time no matter how many sidebars. It even works if you nest get_sidebar calls within other sidebars.

<?php

add_action('wp_head', create_function("",'ob_start();') );
add_action('get_sidebar', 'my_sidebar_class');
add_action('wp_footer', 'my_sidebar_class_replace');

function my_sidebar_class($name=''){
  static $class="withsidebar";
  if(!empty($name))$class.=" sidebar-{$name}";
  my_sidebar_class_replace($class);
}

function my_sidebar_class_replace($c=''){
  static $class='';
  if(!empty($c)) $class=$c;
  else {
    echo str_replace('<body class="','<body class="'.$class.' ',ob_get_clean());
    ob_start();
  }
}
?>

Example sidebar.php with multiple sidebars

Here is an example of a sidebar.php with multiple sidebars. This would result in the body class having "withsidebar sidebar-top sidebar-special sidebar-bottom" added to it.

<?php

<div id="sidebar">

<?php get_sidebar( 'top' );?>
<?php get_sidebar( 'special' );?>
<?php get_sidebar( 'bottom' );?>

</div>
?>

Notes and Thoughts

I use the development version of WordPress, so this will work on any version of wordpress 1.5.0 to beta, and will definately work for the next 100 versions of wordpress.

I love using create_function like this, really as much as I can as it produces more optimized code and optimized execution environments, though it is more confusing to read, especially if you are unfamiliar with it. I also really find the static variable useful. Last thought, I really love wordpress's actions and filters and the hooking ability. Way cool!

Using this basic idea, you are unlimited by what you want to do with your site. You now know how to change and modify the output produced by wordpress after it is produced, but before it is shown to the browser, the possibilities are exciting.

Tags

October 7th, 2011

Comments Welcome

  • lwoods

    Hi, Chuck

    I really like your use of 'static' to modify the body tag but aren't you taking a chance with the output buffering? What happens if some third-party plugin clears the output buffer before 'wp_footer' is called?

  • http://www.askapache.com/ AskApache

    Yes it's not as robust a solution as I normally prefer. I actually updated this for now on my own site. Now I grab the final output buffer in the wp_footer, then do the class replacement using str_replace if the global variable for having the sidebar is registered.

    echo ( (bool) $aa_with_sidebar ? str_replace('<body class=&quot;','<body class=&quot;withsidebar ',$buf) : $buf );


Related Articles


My Online Tools
Popular Articles


Hacking and Hackers

The use of "hacker" to mean "security breaker" is a confusion on the part of the mass media. We hackers refuse to recognize that meaning, and continue using the word to mean someone who loves to program, someone who enjoys playful cleverness, or the combination of the two. See my article, On Hacking.
-- Richard M. Stallman









[hide]

It's very simple - you read the protocol and write the code. -Bill Joy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License, just credit with a link.
This site is not supported or endorsed by The Apache Software Foundation (ASF). All software and documentation produced by The ASF is licensed. "Apache" is a trademark of The ASF. NCSA HTTPd.
UNIX ® is a registered Trademark of The Open Group. POSIX ® is a registered Trademark of The IEEE.

+Askapache | askapache

Site Map | Contact Webmaster | License and Disclaimer | Terms of Service

↑ TOPMain