Adding to $body_classes in a custom Drupal theme
I thought I'd pass on some info in case anyone using Drupal 6 is trying to do something similar which I just wrestled with.
I'm developing a revision to this site and in updating my site's look I decided to change some of the columns and add a region. Just for some basic info, I've moved both default sidebars to the right of the content area and created a new region called "above_sidebars" that is the combined width of the sidebars.
I quickly realized when neither of the sidebars were displayed the content region would change from 560px wide to 960px. This width change was coming from the CSS markup for ".no-sidebars #content" in the styles.css file. I couldn't just change the width setting because I needed to be able to remove all sidebars and including my new above_sidebars and allow the content to run the full width of the site.
The CSS class ".no-sidebars" was being inserted in the body statement for the page.
<body class="front page-node no-sidebars lightbox-processed">
These CSS classes "front", "page-node", "no-sidebars", and "lightbox-processed" added by a page creation variable in Drupal 6 that originated in the Zen theme in Drupal 5. It allows pages to be dynamically themed without having to place tons of conditional statements in their page.tpl.php or other theme pages. Instead the information is worked out in the Drupal code. The name of the variable used to print out the CSS classes may vary based on your theme. Mine is $body_classes.
The variable $body_classes inside the page.tpl.php page tells Drupal to print out CSS class information based on the page, sidebars, and other content being displayed. The line in my theme responsible for this is:
<body class="<?php print $body_classes; ?>">
and this creates html that looks like
<body class="front logged-in no-sidebars admin-menu">
This dynamic class creation allows the person themeing the page to specifically target areas in their theme based on the body statement classes. This means you can change the width, color, margins, or other CSS styles of the page based on whether 1 sidebar, 2 sidebars, or no sidebars are displayed.
Drupal has 3 default columns in basic theme and is set to place a value in $body_classes based on the layout of the current page being displayed. It is set with "no-sidebars," "sidebar-right," "sidebar-left," "one-sidebar" or "two-sidebars." My problems is that the only solution that works for my new region is the class setting "two-sidebars" but that class won't be printed out if one or none of the regular sidebars are displayed.
In seeing this my initial thought was to just place the two-sidebars in the class for the new region when it was printed in page.tpl.php. This would work for the above-sidebars region but not for the content region which is referenced by one of these CSS markups in the css.style file.
.no-sidebars #content
.sidebar-right #content
.sidebar-left #content
.one-sidebar #content
.two-sidebars #content
With the CSS class of ".no-sidebars" the content area ran the full width of the site (960px) and the above_sidebars region was being printed on top of the content region. With my added region I was having problems and I couldn't figure out how to fix it for a while. I was trying to fix the issue while staying within the confines of the 5 different classes that I knew would control the width of the content area. I soon realized I needed a new class or atleast to be able to set the ".two-sidebars" class in the body statement when the above_sidebars region was used.
The only way to actually adjust the class being printed is by forcing drupal to bend to my theme's will. I opted to create the "above-sidebars" class for the new region to make it clear what was happening and for any future adjustments I might need to make that may be different than when both the sidebars are printed.
Now came the question. How? When I need to tackle these type of Drupal tasks I can usually get an answer pretty quickly. My Drupal-foo may not be that strong, but my Google-foo can usually get me the solution to the problem.
But as I started searching "sites:drupal.org adding to $body_classes" or some derevation there off, all I could find was the default api pages or a page cryptically describing a way to add the url into the $body_classes. This got me half-way to my solution. It showed me I could add something to $body classes, but I wasn't completely understanding the php and variables being used. I needed something a bit simpler than what was being shown.
Eventually after sifting through a couple dozen pages on drupal.org and other drupal developer sites, I stumbled upon http://drupal.org/node/341444 and into my solution. On that page Todd Nienkerk responds to someone's problem to the Themer module.
"Here's an example:
function THEME-OR-MODULE-NAME_preprocess_page(&$variables) {
/*
* Add more body classes
*/
$body_classes = array($variables['body_classes']);
// Show/hide admin area using CSS
if ($variables['is_admin']) {
$body_classes[] = 'admin-panel';
}
// Add new body classes to existing variable
$variables['body_classes'] = implode(' ', $body_classes);
}
Of course, page.tpl.php needs to print the $body_classes var passed to it from this function:
<body class="<?php print $body_classes; ?>">"
And this spawned my adaptation into my own theme.
function tnpbrown_preprocess_page(&$vars, $hook) {
/* *
* Pre-Page creation Process to add a body class for above-sidebars
*/
// Pull in all the body class variables currently set
// into the variable in this function so it can be edited
$body_classes = array($vars['body_classes']);
// Check to see if the region is being used and if so
// then adds the region CSS class to the variable.
if ($vars['above_sidebars']) {
$body_classes[] = 'above-sidebars';
}
// Add the new body classes to the existing variable and
// push back into the default variable used in theme creation.
$vars['body_classes'] = implode(' ', $body_classes);
/**
*End adding body class for above-sidebars
*/
}
Basically what happens in my fuction is:
1) The variable $vars is told to hold the data coming from Drupal for the page creation process. This holds the $body_classes value of "no-sidebars", "sidebar-right", etc. as well as the page content, the variables being used and anything else that Drupal creates when putting together the page.
2) Then we tell the $vars array variable to take the body_classes settings it may already contain and copy them into our new $body_classes array variable. So this take anything classes drupal may already know about and places them into our new variable.
3) Then we look at the value of $vars['above_sidebars']to see if it has been set. If it has been created, then Drupal is going to be printing out that region in the creation of the page it is working on. If it is set we want to put the 'above-sidebars' CSS class value into the $body_classes array.
4) Finally we copy the $body_classes array variable back into the $vars array which allows drupal to go on it's merry way in finishing the page creation with our new CSS class added to the global $body_classes variable inside of $vars.
So after all of this, I can now get
<body class="front logged-in no-sidebars above-sidebars admin-menu">
This doesn't remove the css class no-sidebars, but that is ok because I can override that CSS with the the CSS for the above-sidebars class.
If you have questions about this or anything else I'll answer or point you in the best direction I can.











Comments
trying to hide one column on basis of url
hey,
I have almost a similar situation like yours.
In my case I have created a sub theme from zen theme.
But I needed one more column i.e in total 4 columns.
So i added a new column to layout.css as secondsidebar-right.
Now the hard part is that for some menus i have to show the above column and for other I have to hide it i.e I need to switch between 3 and 4 column on basis of the url.
Can you guide me how to do it..
If I can, I'll try to
If I can, I'll try to help.
For me, in order for my new column to work right and to disappear when there is no content in the column and appear when I wanted it to I had to change some of the logic in page.tpl.php and a bit of the CSS. That was the first step.
The code in page.tpl.php I created to control showing or hiding the new column may be a little involved (or even badly written, but it works) but basically I'm telling drupal to print the new column when there is content in the column. Then I created a css class for the new column div so I could easily style the columns. It is a little more involved than that but that is the bare basics. Here's the code from the page.tpl.php page
So I went from the normal Zen code of
<?php if ($left): ?>
<div id="sidebar-left"><div id="sidebar-left-inner" class="region region-left">
<?php print $left; ?>
</div></div> <!-- /#sidebar-left-inner, /#sidebar-left -->
<?php endif; ?>
<?php if ($right): ?>
<div id="sidebar-right"><div id="sidebar-right-inner" class="region region-right">
<?php print $right; ?>
</div></div> <!-- /#sidebar-right-inner, /#sidebar-right -->
<?php endif; ?>
which determines what columns to print out and the corresponding CSS if they exist. I changed it to this:
<?php if ($above_sidebars): ?>
<div id="above-sidebars"><div id="above-sidebars-inner" class="region region-above-sidebars">
<?php print $above_sidebars; ?>
</div></div> <!-- /#above-sidebars-inner, /#above-sideebars -->
<?php endif; ?>
<?php if (($left) && ($right)) {?>
<div id="sidebar-left"><div id="sidebar-left-inner" class="region region-left">
<?php print $left; ?>
</div></div> <!-- /#sidebar-left-inner, /#sidebar-left -->
<div id="sidebar-right"><div id="sidebar-right-inner" class="region region-right">
<?php print $right; ?>
</div></div> <!-- /#sidebar-right-inner, /#sidebar-right -->
<?php } elseif (($left) || ($right)) { ?>
<div id="one-sidebar"><div id="one-sidebar-inner" class="region region-left">
<?php if ($left): ?>
<?php print $left; ?>
<?php endif; ?>
<?php if ($right): ?>
<?php print $right; ?>
<?php endif; ?>
</div></div> <!-- /#one-sidebar-inner, /#one-sidebar -->
<?php } ?>
This does a similar thing as the previous code but it makes allowance for the new sidebar area called above_sidebars and the appropriate CSS to display the sidebars correctly depending on whether the left, right or above_sidebars are being printed.
That bit of coding and the CSS changes I made to change the size of columns based on the CSS printed by that code controls the page. If there is nothing being printed in a column then the div and classes for those corresponding columns won't be printed.
To print or not to print the block items in the column is controlled by the configuration of each individual block item in the administration block page. Go into the configuration for the block items you want to show or hide on specific pages and enter the URLs there. That should do it.
Hope that helps. If you need more help contact me through the contact form up above and we can email more about it.
Thank you very much for the
Thank you very much for the excellent and useful subject.
louboutin
I love your website! did you create this yourself or did you outsource it? Im looking for a blog design thats similar so thats the only reason I’m asking. Either way keep up the nice work I was impressed.come from christian louboutin
Thanks for Your Sharing
I'm recently digging into this field and happy to stumble onto your site. You've posted the info I need. Thanks for the sharing.
Post new comment