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.
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.
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 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();') ); ?>
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(); }
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.
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(); } } ?>
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> ?>
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.