Hacks, tips and tricks

Moshe and merlinofchaos for pointed me in the right direction for the function to modify if you want to remove divs that are output in a list view block via the Views module. To strip out those divs, do something like below in your PHP Template's template.php file:

function phptemplate_views_view_list($view, $nodes, $type) {
  $fields = _views_get_fields();
  foreach ($nodes as $node) {
    $item = '';
    foreach ($view->field as $field) {
      if ($field['label']) {
        $item .= '<div class="view-label view-label-$field[queryname]">'. $field['label'] ."</div>";
      }
      $item .= views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "<br />";
    }
    $items[] = "$item"; // l($node->title, "node/$node->nid");
  }
  if ($items) {
    return theme('item_list', $items);
  }
}

Thanks to everyone for the suggestions.

It always bugged me that the a destructive button like Delete has the same weight in Drupal forms as Preview and Submit. To try and prevent clicking on destructive buttons, I find it a good practice to make those buttons less important, yet still available. To do that, you can simply style each of the button types Drupal puts out--edit, submit and delete. Here's an example making the submit button boldest, and removing the button style of delete.

#edit-preview {
  border: 2px solid #CACC00;
  color: #A6A800;
}
#edit-submit {
  border: 2px solid #769405;
  color: #668004;
}
#edit-delete {
  background: none;
  border: none;
  color: #999;
}

I've been using Crank Brothers Eggbeater pedals on my fixed gear bike since the Fall and decided at the beginning of the year to use them on my newly built up road bike. If you aren't familiar with them, the diminutive Eggbeater pedals are typically used on Mountain Bikes and have a single spring interface allowing 4-sided entry. They are elegant, simply designed pedals and because of the open design of the clips, they allow mud to easily be cleared, a bonus for off road riders. You can read a good review of the pedals here.

So I 've been using these pedals for the past 6 months. They are working fine for the short, flat city riding I do around town on my fixie and even performed well on the training rides I've been doing on my road bike in Central and Prospect Parks. But in the last few weeks, I've been doing hillier training rides on Route 9W and River Road and have started to feel hot spots on my feet.

If you don't know what they are, hot spots refer to the the sore and hot feeling you get on your feet at the point where your shoe cleats make contact with the pedal. As you can see from the image of the Eggbeaters above, the pedal only makes contact with your shoes on the two horizontal points that engage the cleat. This is fine most of the time for me, but when I do longer rides or when I mash down on the pedals a little more on climbs, I've started to feel the hot spots. So, of course, I've been reading around on the forums to see if other people are having this experience.

Turns out that some other roadies do get hot spots with Eggbeaters. Some of these folks really like the simplicity of the Eggbeater design, as I do, and are reluctant to go with other pedals. So what a few people have suggested is to look at the Crank Brothers Quattro SL Road Pedals, a shoe made for roadies that features the same single spring clip interface, but also includes a platform to make contact with your shoe. Sounded like a decent idea, so I got interested in buying a set. Problem is, I ride with Sidi Dominator 5 Mega shoes, a cleated mountain bike shoe, and I was worried that the rubber cleats on the side of the shoe would interfere with the pedal platforms. I contacted Crank Brothers to see if that was the case, and sure enough it is. The photo below shows where the cleats make contact with the pedal.

I'm not about to keep switching cleats on my pedals and definitely won't drop more money on a second pair of shoes. Luckily, the folks at Crank Brothers told me that it is possible to use the Sidi Dominators with the Quattro if I modify the shoe so that the rubber cleat on the inside of each shoe near the pedal contact is shaved down a little.

This cleat bumps into the pedal's inboard bearing cover, making it nearly impossible to clip out. The modification is really quite simple though. I took an exacto knife and shaved away the cleat at an angle that would allow the bearing cover to clear. See the photo below for cutting area. As noted in the comments by nicobot, how much and wear you shave the rubber cleats depends on the cleat position and shoe size. As you can see from the photo, my cleat is situated to the furthest back position, which happens to put it closer to the ball of my foot.

Simple modification. And now I can use my favorite shoes with a Crank Brothers pedal and be happy. So far the feel has been great. The shoe's side cleats are making contact with the pedal platform, so I'm assuming that I'll be rid of the hot spots. If that's not the case, you can be sure that I'll be bitching about it here later.

Here's a tip that only an information geek would care about. If you've ever looked at my taxonomies, you'll know that I describe nodes by facet, e.g. file format, person, subject. Years ago, in another version of Drupal, I used to show terms applied to each node by facet, but with the upgrades and changes to the taxonomy module, I gave up trying to keep that up to date. Luckily, I found in the PHP-Template documentation, that someone posted a snippet for sorting/displaying terms by vocabulary. So I'm using this snippet to display my terms by facet again.

Here's a screenshot of terms in action:

Like I said, that's the kind display of metadata that only a info geek would want. But I think it also demonstrates to people new to Drupal the kind of description/categorization of content that might be useful in different environments, e.g. a corporate intranet.

So to do this, use the following code in your node.tpl.php (snarfed from drupal.org):

<?php if ($terms): ?>
<?php /* sort taxonomy links by vocabulary 27 */
$terms27 = taxonomy_node_get_terms_by_vocabulary($node->nid, 27);
if (
$terms27) {
  print
'<div class="terms">Forums: ';
     foreach (
$terms27 as $key => $term27) {
    
$lterm27 = l($term27->name, 'taxonomy/term/'.$term27->tid);
  print
$lterm27.' - ';
     }
  print
'</div>';
}
?>

<?php endif; ?>

You would repeat that code block sandwhiched between "if($terms) ... endif" for each set of facets you want to display.

The previous grid article dealt with how to come up with a CSS strategy when you're working with another visual designer's comps. Now I'd like to discuss doing grid-based theme design for open source content management systems, e.g. Drupal and WordPress. The purpose of this article is to give you an idea of how to approach blog theme design using a grid system. After reading this, you should be able to create a fully-functional grid-based design and HTML prototype that can be coverted into a theme template.

Creating the design grid

I recently redesigned this site because I wanted a layout that provided larger areas for my content. I needed a system that provided me the flexibility to get creative with the layout, but I also wanted to be sure not to lose control of the order and balance of page elements. While the spare layout of my previous design worked well, the new design would be a little more information dense.

For the new layout I used a grid with a simple division of thirds at a fixed width of 801 px. To get to this width, I played around with different sizes that could be centered within a 1024px x 768px browser window with ample white space on the sides. I targetted my maximum width around 800px.

I started by dividing up 800px into thirds and had an approximate width of 267px per third to play with. I borrowed the idea from the MIG design of using a 3 pixel border to separate each division. This odd-sized gutter makes room for 1px vertical border lines with 1px of padding at each side if I need it. I kept sub-dividing the thirds and after a bit of tweaking came up with the grid below. Each little pink box is 1/12 the width of the page (64px wide). 4 of these side to side make up a third of the width, which I would use for normal column of text. 2 or 3 of these side to side would be nice for a narrow column.

grid
Screen shot of the grid (shrunken to fit)

So now I have a grid that could easily be divided into the thirds I needed to make a multi-column layout. This gives me a very simple grid to work with and I don't think I'd need to have smaller grid divisions for blog themes. Next step is to start looking at layout sketches I had in mind and think about how to turn them into XHTML & CSS. The visual design I'm basing this demo on is an old theme I once used on my blog, with a little modification of the graphics and color palette. You can see a screenshot of the old theme (it's the one in the upper left hand corner).

Turning boxes into content areas

To get started, I think about the page elements I want to use. I want the page to have these parts:

  • header
    • logo
    • graphic element
  • body
    • weblog content
      • blog entry
        • entry metadata
        • comments
    • local navigation
    • advertisements
  • footer

I have some hierarchy of elements established in this list. You probably won't need to jot down a list of elements like this to do a weblog layout, but it helps to show where we're going.

Using the list as a starting point, I start to think about where I want these elements to go on the grid. You can use the grid like a wireframe (page schematic) by selecting areas of content and blocking them out, labeling them as you go.

grid template
Wireframe of content areas

Above, I took each of the page elements and blocked them out. We're going to take the wireframe and create the visual design elements for the page and design the layout of the content blocks.

grid template
Visual design comprehensive sketch over grid

As I'm doing this design, I realize that I don't actually need 3 grid blocks for the ads, so I use 2 instead. The layout is looking good to me so far, so now I start thinking about how to turn the blocks into CSS.

Turning content areas into CSS elements

Working with grids makes it easier to visualize a strategy for the CSS layout. I start by thinking of the hierarchy of divs that will make up my page wrapper and all of the child divs nested within it. I'll label those in the wireframe to show what I'm thinking.

grid template

As you can see, I'm going to enclose the entire page in div#wrapper. The rest is a bit like a sandwich. On the top, I put the #logo and #graphic in div#header. On the bottom, I have div#footer with my copyright info. And sandwiched in the middle is div#main which encloses the 3 column layout of #localnav, #content and #ads.

Next I go about measuring each content block and recording it's dimensions. I'm mainly looking for widths here except for the header, where I actually want the height as well. Heights will, of course, stretch vertically in the div#main. I measure the #header out to be 801px wide by 131px high. In the screenshot below, I show how I get the dimensions of #logo using the Info panel in Photoshop. I do this to each content area, getting fixed widths for all the areas.

mesuring content modules

Creating the style sheet for the layout

Constructing a shell

When I'm done gathering my measurements, I can start to construct the stylesheet. I start by creating a barebones shell that will look a bit like our wireframe. First I record the main divisions in my CSS file.

#wrapper {}
#header {}
#header #logo {}
#header #graphic {}
#main {}
#main #navigation {}
#main #content {}
#main #ads {}
#footer {}

Then I put in all the dimensions and positioning. To test my sanity and the precision of my measurements, I put the grid into the div#wrapper as a background image. The core CSS for the layout is below.

* {
  padding:0;
  margin:0;
  font-family: Helvetica, Arial, Sans-serif;
}

body {
  background: #fff;
  text-align: center;
}
#wrapper {
  text-align: left;
  margin: 20px auto;
  width: 801px;
  height: 801px;
  background: transparent
    url(grid-unit-boxes-801px.png) 0 0 repeat-y;
}
#header {
  margin-bottom: 3px;
}

#header #logo {
  float: left;
  margin-right: 3px;
  width: 198px;
  height: 198px;
  background: #ccc;
}

#header #graphic {
  float: left;
  width: 600px;
  height: 198px;
  background: #ccc;
}

#main {
  margin-bottom: 3px;
}

#main #navigation {
  float: left;
  margin-right: 3px;
  width: 198px;
  background: #ccc;
}

#main #content {
  float: left;
  margin-right: 3px;
  width: 466px;
  background: #ccc;
}

#main #ads {
  float: left;
  width: 131px;
  background: #ccc;
}

#footer {
  background: #ccc;
}

/* PIE easyclearing */
.clearfix:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
}

.clearfix {display: inline-table;}

/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
.clearfix {display: block;}
/* End hide from IE-mac */

Next I start putting the widths (and heights for the #header) I recorded into the style sheet, creating a shell for the site. To make the boxes lay out precisely, I use left floats for columns and the Position Is Everything easy clearing method. If you view a demo of the CSS shell pop you'll see that the boxes line up precisely against the background grid. Things are looking pretty good. Now we have to add the graphic elements from the comp.

Completing the wrapper

We're almost done now with the wrapper. To finish off the wrapper we have to cut up the background graphics and tweak the the widths just a little so that our border backgrounds fit around the grid. Take a look at the wrapper with header graphics and borders in place pop.

Final touches

It's looking nearly finished now. All that's left is to do the style elements for the HTML inside the major divs. I put in all of the HTML for the template areas. I create the site logo and drop that into div#logo. I add some padding to the columns inside div#main. Finally, I add color and sizes to the fonts. Now you can view the final HTML template pop.

Conclusion

Grids are very useful for doing even simple blog themes. They give you a solid system you can rely on to lay out your template and evolve it as needs require.

I showed you how I approach layout and site development for a weblog template and gave you an HTML prototype you can convert into a theme. You are free to use the template in this example, I'm releasing it under GPL. I hope this article helps Drupal developers in some way by giving them a process for approaching their theme designs. Have fun theming!

See also: Cutting and sewing grid-based design: Part 1, working with other people's comps

This one surprised me because I didn't know you could do this so easily until I read it in the support email list. If you want to supress the display of author, publication date and taxonomy terms, do as David Metzler suggests:

  • Go to the Administer -> Themes menu
  • Select the "Configure" tab
  • Uncheck "Display Post Information" for the appropriate content type

I used to just modify the theme. But this is simpler if all you want to do is stop displaying the metadata. Nice one.

This is another simple little trick. I've gotten asked a few times how I got the URLs to display on my weblink entries. For an example look below the body of this entry:

See the little globe icon with the URL? It's easy to modify the node.tpl.php to conditionally format weblink entries. Just check for the node type using this code:

<?php
   
if ($node->type == 'weblink') {
      print
'<a href="/drupal-4-7-2/'. $node->url .'">'. $node->url .'</a>';
    }
?>

Simple, no? You can do that with any type, e.g. page, blog, poll, etc.

Update Weitzman (Moshe?) gave another nice alternative: "Copy node.tpl.php to node-weblink.tpl.php. Then you can customize fiull display of each node type." Even simpler!

Today's tip is simple, but potentially very useful to someone. One of the things you might notice if you visit some of the popular commercial blogs is that they sprinkle ads throughout their list of blog entries. For example, on your blog page, you might have a row of ads after the 2nd and 6th blog entries or something. Tweaking your ad placement is one sure way to increase your click-throughs. Doing this in Drupal is easy.

In your PHP Template theme, the node.tpl.php file controls the display of your nodes listing (e.g. node/ and blog/ pages). If we wanted to put an ad after the 2nd and 6th blog entries, we can put this code at the top of that file:

<?php if ( !$page && ($id == 2 || $id == 6)) : ?>
[replace this comment with your ad code]
<?php endif; ?>

The first part of the if statement (!$page) checks to make sure we're not looking at a single node page, e.g. node/view/1. The second part ($seqid = = 2 || $seqid = = 6) says to apply this code only to the 2nd and 6th entries on the page. Just change the numbers to wherever you want the ads to appear. Then drop your Ad code (e.g. from Google Adsense) in to replace the comment. To see what this looks like, check out the Weblog page on this site.

Note: According to http://drupal.org/node/46209 $seqid becomes $id in 4.7

Since redesigning this site, I've been getting a ton of requests for Drupal theme design. Most of the projects are too small for me to take or require too much work for the amount of money people have budgeted. So to help people who are new to doing theme design with Drupal, I'm going to start a series of tips on getting more out of your Drupal themes. My focus will be on using the PHP Template engine for my examples because it's the best option for flexibility of your theme design. I should note that not all tips will be theme specific, however. This first tip is really about re-using content blocks in pages.

The portal model

Some of you may be familiar with the concept of portlets inside portals like Oracle Portal or some such. Portlets are little windows of content that you insert into a portal page. So you might have a page on a topic, e.g. Human Resources in your portal. But to populate that page, you may take existing content from other sections of your portal. To do this, you select a portlet from your admin menu and tell your portal page to use it. You typically select a bunch of these to build up a page's content.

In Drupal we can do similar things to populate content, but this type of modular approach to individual page building is usually left to content management systems like Mambo/Joomla and the commercial portal CMS's. To stack blocks of content in Drupal, we need to do a little more work and take a few more steps, but it's doable. One approach is to build your content modules within Drupal's block system. And then when you create a new page (has to be a PHP page), you simply insert block calls into your page body.

Here's an example showing how a typical portal page is built and how you might build a Drupal page with blocks in a similar manner:

screenshot

So you see that what I plan to do is display a block using PHP. To give you an example, let's take a to do list. I'm a fan of the GTD method of time management, so I created a new "To do items" content type using flexinode. Taking that example in the diagram above, I want to insert a block of my latest to do items in a content area on the left, and a list of new links I've tracked in a content area on the right.

Inserting blocks in Drupal pages

To insert the blocks, we use some PHP code in the page body and be sure to select "PHP code" for the Input format. (More on this technique in the Drupal node: Placing the contents of a block in any location.)

PHP code to insert my to do list

For this content area, I created a block that does an SQL search for my to flexinode-5 items. Then I use the module_invoke() function to display the block within the page. Note that "7" is the ID number of the block I created in the admin -> blocks menu.

<?php
$block = module_invoke('block', 'block', 'view', 7);
print $block['content'];
?>

Alternatively I can simply insert the PHP with the SQL statement into the page itself like so:

<?php
$sql = "SELECT node.title, node.nid FROM node WHERE type='flexinode-5' ORDER BY node.created DESC LIMIT 50" ;
$output .= "<ul>";
$result = db_query($sql);
while ($anode = db_fetch_object($result)) {
$output .= "<li>".l($anode->title, "node/$anode->nid")."</li>";
}
$output .= "</ul>";
$output .='<div class="more-link"><a href="to_do_list" class="small">more</a></div>';
print $output;
?>

Displays this:


PHP code to insert latest blog entries

<?php
$block = module_invoke('blog', 'block', 'view', '0');
print $block['content'];
?>

Displays this:


Wrapping it up

That's it really. You can then use CSS to format your columnar layout. Very simple method to get near portal-like functionality. Might be nice if the "Page" content type used the content management model so we select blocks of content from within the "Create" interface and move the blocks around. That would require an entirely new administration UI, however.

If you get comfortable with the method above, this might be a suitable approach for re-using content in pages. This is one method I would definitely try using in client's sites, but your site administrator will have to be familiar with PHP to create these kinds of blocks. Anyone who's wanting this kind of functionality and who is not comfortable touching PHP might be better served by other CMS packages.

NOTE: This entry was created in 2005. I'm not using skins on this site anymore, so you can select a different skin, but the code below should work, although a method may be provided to do this with a module now.

This past year I've learned how to do a few things a little better as a site developer. The work I did for Winning Connections and Management Innovation Group sites led me to come up with better ways to architect and improve my markup and style sheet strategy. Working closely with the MIG visual designer also allowed me to come up with better ways for converting a grid-based design to CSS (a topic I'd like to write a lengthier article on later). So I wanted to incorporate some of that learning into this site's design and code. Here's the first set of notes on how I'm starting to evolve this site.

Visual design

The visual design incorporates some of the design elements I used in previous skins a year or two ago. If you've followed my skinning explorations, you might remember those. I like simple, minimal and spare design, but I really react to colors, especially warm ones. I've been looking at the white pages on this weblog every day for the last year and was really missing having warm colors on my screen. So they're back, but, guess what, you can also select a white background too if you're not into the colors.

Here's a comparison of the new skin with some of the site's previous designs:

All were pretty minimal, but the design before this (bottom left in the picture above) was the most spare. I really liked the home page and think that design would have lasted a long time. But I wanted to get a few messages up on the home page -- mainly that I do freelance work now -- so you can see in the screenshots what a big change has occurred in the use of white space. But that design was really a splash page, so I'm comfortable giving up a little on having that quiet page for a little purposefulness.

The version you see live on the site right now is called skin 2. Skin 1 is the white one in the bottom right corner of the picture above. It's the first skin I've had with a background color in a long time. I'm not sure if I'll keep that as the default or use the white one yet. Right now I'm liking the orange background so I'm going to leave that up for a few days and consider setting skin 1 (white background) as the default.

Drupal blocks

I completed the first part of this redesign, creating the new theme files which use blocks more effectively to generate local navigation where necessary. Previously in the non-blog sections, I didn't have any local navigation in areas that needed it, so the back button or the global nav links were the only way to jump back up to a parent. I'm using a PHP snippet in my blocks with a simple array to put out the local nav. I could have done some searching for taxonomy terms to generate that bit, but I wanted a bit more control of the display. The script also searches the URI and if it matches the location in the array, makes the current local nav link appear selected (bold and black). I wish there were an easier way to do that on pages out of the box. I like how WordPress' page model uses parent-child relationships and generates this tree for you.

Now that I know how to use Drupal blocks a little more effectively, I'm really impressed with how much more I can do. I had previously been using the Side Content module (another excellent module, by the way) to output per-page sidebars, but using blocks for entire sections is much more powerful. I'm digging that.

Here's the code I used to generate the local nav in the Services section:

<?php
$dapath
= $_SERVER["REQUEST_URI"];
$MenuArr =
  array(
   
"Overview"=> "/personal/services/overview",
   
"Philosophy" => "/personal/services/philosophy",
   
"Portfolio"=> "/personal/services/portfolio",
   
"Curriculum Vitae"=> "/personal/services/curriculum_vitae"
 
);
$output = "<ul>";
foreach(
$MenuArr as $label=>$link) {
  (
eregi($link,$dapath)) ? $class='class="selected"' : $class=NULL;
 
$link = eregi_replace('\$','',$link);
 
$link = eregi_replace('\*\.\*','',$link);
 
$output .= "<li><a href=\"$link\" $class>$label</a></li>";
}
$output .= "</ul>";
return
$output;
?>

The Publications and Weblog sections also use the Similar Entries module to show "More like this..." type related nodes. I also like the Side Content module, so I have that installed to add sidebar blocks per-node, but I'm not using them anywhere yet.

Drupal front_page.module

I also have the front_page.module working for me. I had actually been using a script I created with adodb to generate the home page because front_page hadn't been created at the time. front_page is another indispensable module if you don't want a cookie-cutter blog, which this site is not. This is one of the reasons Drupal and WordPress are so well-suited as content management systems. The customization options are very good if you know what modules to install.

The PHP Snippets section of the Drupal docs has some great tips for selecting and displaying lists of nodes. Here's the code I used for putting out "New on this site" part of the home page.

<?
$sql = "SELECT node.title, node.nid FROM node WHERE promote='1' ORDER BY node.created DESC LIMIT 10" ;
$output .= "<ul>";
$result = db_query($sql);
while ($anode = db_fetch_object($result)) {
$output .= "<li>".l($anode->title, "node/$anode->nid")."</li>";
}
$output .= "</ul>";
$output .='<div class="more-link"><a href="/drupal-4-7-2/weblog/" class="small">more</a></div>';
print $output;
?>

I learned how to put links from my aggregator into the front page by reading this page on drupal.org: Placing the contents of a block in any location. Here's the PHP snippet I used for the "Elsewhere" content on the home page. This basically tells Drupal to output the aggregator block for category # 6.

<?php
$block
= module_invoke('aggregator', 'block', 'view', 'category-6');
print
$block['content'];
?>

Skins are back!

I've also updated my skinning script to work even though Drupal is caching pages. I did a little workaround by forcing a CSS file to be generated using PHP. That way I can check the cookie to see what the user has set for their skin and use that value in the CSS file rather than in the cached HTML pages Drupal generates.

To force the Apache server to execute a CSS file as PHP, I created an .htaccess file in the directory containing the theme.css file. The .htaccess file contained this text:

<Files theme.css>
SetHandler application/x-httpd-php
ForceType application/x-httpd-php
</Files>

The skinning script works by setting a cookie on your browser with a numeric value. Right now there are only two values, 1 and 2. The theme.css file checks to see what the cookie value is and uses that number to reference the appropriate CSS skin. Here's the PHP code for theme.css:

<?php
header
("Content-type: text/css; charset=UTF-8");

if (
preg_match("/[0-9]/", $_COOKIE["UrlgreyhotSkin"]) ) {
 
$UghSkinVal = strip_tags(trim($_COOKIE["UrlgreyhotSkin"]));
} else {
 
$UghSkinVal = 2;
}

?>

(Thanks to Ed Costello suggesting putting in security measures check in the script above.)

Then you create your skin selecting page, which lists the available skins and has the function for setting the cookie. I won't go into that here, but I use a script I created for doing this that uses some of the PHP from my old skinning script.

More to do

Of course, the remaining part will be to do the minor realignment of the content areas, e.g. the portfolio is moved under the heading "Services" now. Since I've started doing a little freelance in the past year, it seemed like time to make this site a bit more service oriented so I can market what I do. Along with that will be the long needed update of the Lucent Technologies section of my portfolio, which hasn't been updated in 4 years. That will be the biggest part.

Still working on a style sheet for Mac IE 5. Sigh. More to come.