Styling the first word in a block title (or "It's time for a PHP explosion!")
Note: I posted a better solution at Styling the first word of a block title (preprocessing edition). I left this post online only to reference the extremely helpful comments that improved it. Thanks, everyone!
I'm working on a theme that that needs the first word in all sidebar block titles bolded. The most obvious way to do this is with jQuery (here's a comment that shows a couple ways to do it). But I wanted to see how tough it would be to use PHP to wrap a span around the first word of all block titles before they were rendered. Not too tough, as it turns out, though it did take some brushing up on my admittedly rusty PHP skills.
As is my custom, I'm going to go into more detail than is probably necessary. If you want to just get the code, feel free to skip to the Result heading.
The Process
First, I copied block.tpl.php out of my base theme (in my case, sites/all/themes/omega/omega/templates/block.tpl.php) and into my theme directory.* Here's what that file looks like:
<?php $tag = $block->subject ? 'section' : 'div'; ?>
<<?php print $tag; ?><?php print $attributes; ?>>
<div class="block-inner clearfix">
<?php print render($title_prefix); ?>
<?php if ($block->subject): ?>
<h2<?php print $title_attributes; ?>><?php print $block->subject; ?></h2>
<?php endif; ?>
<?php print render($title_suffix); ?>
<div<?php print $content_attributes; ?>>
<?php print $content ?>
</div>
</div>
</<?php print $tag; ?>>
Please note that this is provided only as a reference point. Be sure to copy the template out of your base theme, not from here, to avoid differences between theme versions.
The line we're going to change is here:
<?php print $block->subject; ?>
The PHP function to use here is explode. I started by exploding $block->subject and storing it in a variable I named $block_title_explode, because I am not what you might call creative.
$block_title_explode = explode(" ",$block->subject);
This breaks the variable into different parts, using a space -- defined as " " above -- to figure out where it should draw the lines between each part. If you put "," it would use commas as the dividing line (so "value1,value2,value3" would get split into "value 1" "value 2" "value 3"). If you put "|" it would use pipes as the dividing line. You get the idea.
After this, I used a foreach loop to tell the function what to do with each exploded part. Based on the helpful note of a commenter on the PHP manual, I first added a reset, like so:
reset($block_title_explode);
Then I told it what to do with each exploded value:
foreach($block_title_explode as $block_title_exploded) {
echo '<span>' . $block_title_exploded . '</span>';
}
You'll notice that I assigned each exploded value $block_title_exploded, as opposed to $block_title_explode. For more on this, see the PHP manual's foreach page.
The result of this is wrapping a span around every single word. If my block title was Here Is a Block Title, my resulting code would be:
<span>Here</span><span>Is</span><span>A</span><span>Block</span><span>Title</span>
There are two problems here. One is that there's no space between the words. This is very easily fixed by adding a space after the span tag in the foreach loop, like so:
echo '<span>' . $block_title_exploded . '</span> ';
The second is that all the spans after the first one are pointless. Sure, we could use :first-child CSS3 to target the first one, but it's much cleaner (and more browser-friendly, if you have to care about old IEs and can't write it off to progressive enhancement) if we only wrap a span around the element we actually want. A StackOverflow post gave an elegant way to do this, by setting a $first variable to true before the function starts and setting it to false in the foreach. This means that it will still be true when the foreach runs on the first element, and false every time after that. So we can say that if it's true, the function should add the span, and if it's not, it shouldn't.
The Result
<?php
$block_title_explode = explode(" ",$block->subject);
reset($block_title_explode);
$first = true;
foreach($block_title_explode as $block_title_exploded) {
if ($first) {
echo '<span>' . $block_title_exploded . '</span> ';
$first = false;
} else {
echo $block_title_exploded . ' ';
}
}
?>
This goes right where <?php print $block->subject; ?> was in the original file. Finally, I can cap this off with a little CSS that targets the span:
h2.block-title span {
font-weight: bold;
}
Voilà, a bolded first word in each block title. If you only want to target blocks in the sidebar second region, you could tack on .region-sidebar-second to make it more specific.
Now, I'm not a PHP guru by any means, so if there's a more efficient way to do this (like a preprocess solution, rather than one in the block template), I'm all ears. But this worked neatly for me, so I'm hoping it'll help out a few other people with the same troubles. Happy Wednesday!
Note
While copying the original block template out of my base theme, I noticed that there's a block.tpl.php in both the alpha and omega directories of Omega. I originally used alpha's and saw that it broke some of my theming, because my blocks no longer had the block ID as a class, and I'd targeted that class while theming. It was really easy to fix; I just added . ' ' . $block_html_id; to class="<?php print $classes ?>". Later I just swapped it with the template from the omega directory (which doesn't cause that problem), and this is the template whose code is shown above.↩