Remove Node Lists from Taxonomy Pages in Drupal 7

If you use Drupal, you can’t help but love the Taxonomy module. After all, categorizing content goes hand in hand with creating it or managing it, and Taxonomy gives us a nice, flexible framework, especially when you throw fields into the mix.

Unfortunately, every taxonomy term page comes with a default list of all the content classified with that term. Sometimes you might want this, but sometimes you might not. I’ve run into a few situations in which I needed tighter control over the term page display, like that provided by Views, without wanting to override the entire page.

Here’s the snippet of code I created to deal with those situations. Just put the following in the template.php file of your theme folder:

function THEMENAME_preprocess_page(&$vars){   if (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric(arg(2))){     unset($vars['page']['content']['system_main']['nodes']);     unset($vars['page']['content']['system_main']['pager']);     unset($vars['page']['content']['system_main']['no_content']);   } } This will remove the default content list, as well as the pager and "No content has been classified with this term" text if either is present. On a default installation, that sets the page back to a blank slate, like an ordinary content page, so you can play around with it from there to your heart's content.

How to Enable Ubercart Product Image Zoom with Gallery Thumbnails

In my experience, ecommerce websites are their own beasts, with all sorts of specialized functionality that doesn’t get requested on other websites. One of the most frequent requests, and often times one of the most difficult to fulfill, is enabling product image zoom functionality along with gallery thumbnails that can seamlessly swap out the main image. Here is one way to accomplish that on a Drupal 6 website with Ubercart.

  1. Install the necessary modules. For this solution, you’re going to need CCK, ImageField, ImageCache, and Cloud Zoom (I used to prefer jQZoom, but found it to have less compatibility in WebKit browsers).
  2. Set up your image field. The code provided below is designed to work with the default image handling field creating by Ubercart, but it can work just as well with any CCK image field. Just be sure to swap out the $node->field_image_cache variable with the name of your own field if you’re using something different.
  3. Set up your ImageCache presets. You’re going to need three. Again, the solution below is tailored for use with product images in Ubercart, so I’ve named them accordingly. “product_full” is the main image displayed to the user, “product_zoom” is the larger image shown in the zoom window, and “product_thumbnail” is the gallery thumbnail that allows the user to swap out the main image. You can name these whatever you like; just be sure to change their names in the code as well.
  4. Stop the field from displaying. By default, Cloud Zoom can automatically display the image and zoom window without any need to mess with template files. This is very handy, but it doesn’t support gallery thumbnails, so we’ll need to disable the default behavior. Go into Administer > Content Management > Content Types > Manage fields > Display fields and change the Label, Teaser, and Full node drop-downs for your image field to . Be sure not to click the Exclude boxes, or else the template modifications below will not work properly.
  5. Add this code to your theme file. In the case of Ubercart, this goes in node-product.tpl.php where you’d like the images to appear. If you’re using a different content type, use that in place of product. And again, be sure to switch out the image field variable name or the ImageCache preset names if you’re using something different.

    &lt;?php<br /><br />
    
    drupal_add_js(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.1.0.2.min.js');<br />
    drupal_add_css(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.css');<br />
    if (is_array($node-&gt;field_image_cache) && count($node-&gt;field_image_cache) &gt; 0 && strlen($node-&gt;field_image_cache[0]) &gt; 0){<br /><br />
    
      // Display the primary image.<br />
      echo l(theme('imagecache', 'product_full', $node-&gt;field_image_cache[0]['filepath'], $node-&gt;field_image_cache[0]['data']['alt'], $node-&gt;field_image_cache[0]['data']['title']), imagecache_create_path('product_zoom', $node-&gt;field_image_cache[0]['filepath']), array('attributes' =&gt; array('class' =&gt; 'cloud-zoom', 'id' =&gt; 'zoom1'), 'html' =&gt; TRUE));<br /><br />
    
      // Display the gallery thumbnails.<br />
      $num_images = count($node-&gt;field_image_cache);<br />
      if ($num_images &gt; 1){<br />
        for ($i = 0; $i &lt; $num_images; $i++){<br />
          echo '&lt;a class="cloud-zoom-gallery" href="' . base_path() . imagecache_create_path('product_zoom', $node-&gt;field_image_cache[$i]['filepath']) . '" rel="useZoom:\'zoom1\', smallImage:\'' . base_path() . imagecache_create_path('product_full', base_path() . $node-&gt;field_image_cache[$i]['filepath']) . '\'"&gt;' . theme('imagecache', 'product_thumbnail', $node-&gt;field_image_cache[$i]['filepath']) . '&lt;/a&gt;';<br />
        }<br />
      }<br />
    }<br /><br />
    
    ?&gt;
  6. Stylize to taste. With a bit of added coding and some CSS, you can make the final product display however you like. For example, I like to put the gallery thumbnails into an unordered list and float them beneath the main image for ease of usability. Your needs may vary.

How to Add Variations to a Drupal Theme

Recently, I did work for a few clients who needed several very similar websites launched in a single project, each of which using an almost identical (yet subtly different) theme. As I started configuring them on Drupal multi-site installations, it got me thinking: Is there a way to take advantage of the same sort of code reuse within a theme?

There are already options for this, of course, such as sub-themes or the Color module. In my case, however, I decided to try something a little different: I used a custom theme setting to add a CSS class to the body tag, then created the theme variations with pure CSS. Here’s how I did it.

Step One: Set Up the Advanced Theme Setting

In case you’re a Drupal themer who doesn’t know this trick, it’s a life-saver. You can configure your theme with a form to collect custom settings, then use those settings in the theme itself. I like to use this for things like phone numbers that don’t deserve their own block region but need to be configurable by the client nonetheless.

There’s a great Drupal article on advanced theme settings, which I won’t bother repeating. As far as theme variants go, all you have to do is include the following code in the theme_settings.php file of your theme folder:

&lt;?php

function themename_settings($saved_settings){
$defaults = array(
'variant' =&gt; 'default'
);
$settings = array_merge($defaults, $saved_settings);

$form['variant'] = array(
'#title' =&gt; t('Variant'),
'#type' =&gt; 'select',
'#default_value' =&gt; array($settings['variant']),
'#options' =&gt; array(
'default' =&gt; 'Default',
'variant_1' =&gt; 'Variant #1',
'variant_2' =&gt; 'Variant #2',
'variant_3' =&gt; 'Variant #3'
)
);

 return $form;
}

This will create a drop-down selection menu on your theme configuration page that allows you to select the desired variant. Be sure to change the keys and values in the #options array to include the CSS class and variant names you want.

Step Two: Hook the Variant Setting into the Template Files

Now that the variant can be defined, it’s time to dynamically include it in your template files. This is accomplished with the theme_get_setting() function. Include the following code at the top of your page.tpl.php file (and any other relevant template files):

&lt;?php
$variant = theme_get_setting('variant');
if ($variant == 'default'){
unset($variant);
}
?&gt;

Then, on the body tag in each template, include code to insert the variant as a CSS class:

&lt;body&lt;?php echo ($variant) ? ' class=" . $variant . "' : ''; ?&gt;&gt;

If you want, you can do other useful things with the $variant variable. For example, I took it a step farther and created image subfolders at theme_folder/images/$variant. That way, if I had images that needed to vary, all I had to do was name the images the same and include $variant in the image src attribute.

Step Three: Add CSS to Customize Each Variant

Once the body is being classed according to the theme variant setting, you can do whatever you like to customize each variant. Simply add CSS to your style.css file in order to tweak the theme’s appearance according to the new body class. For example, you might adjust the font face and color of each variant:

#content { color:#000; font-family:Arial; }
.variant_1 #content { color:#F00; font-family:Helvetica; }
.variant_2 #content { color:#00F; font-family:Verdana; }
…

Possible Uses

The main use of this technique is to provide a fast, easy way to create minor variations in a single Drupal theme. You might add some seasonal stylization for a holiday variant, for example. Or, as in my case, you might have a few small differences between sites using the same theme and want to keep a common code base for ease of maintenance.

Anything more than that and you’re probably better off using one of the aforementioned techniques, such as sub-theming or the Color module. It’s really just a matter of how different your variations are going to be.

Elsewhere: So You’ve Got a Drupal Website… Now What? (Part Two: Learning the Lingo)

I just posted So You’ve Got a Drupal Website… Now What? (Part Two: Learning the Lingo) on ClickOptimize.com:

In this series, I walk you through the basics of using your shiny new Drupal website. In part one, I explained what Drupal is and why it’s awesome. We’ll get into working with Drupal in the next section. Before we can walk the Drupal walk, however, we need to learn to talk the Drupal talk.

Read the whole article on ClickOptimize.com.

Elsewhere: So You’ve Got a Drupal Website… Now What? (Part One: What is Drupal)

I just posted So You’ve Got a Drupal Website… Now What? (Part One: What is Drupal) on ClickOptimize.com.

It’s shiny. It’s new. And it’s totally mind-boggling how much you can do with it. The only trouble is, you have no idea where to start. In this series, I’ll walk you through all the useful bits and bobs in your new Drupal site, how to use them, and all of the situationally useful extra stuff you can safely ignore 99% of the time.

Read the whole article on ClickOptimize.com.

Attach Files to Taxonomy Terms in Drupal

From what I can tell, there are plenty of ways to attach files to nodes in Drupal, and even a few ways to attach them to users, but none that I could find to attach them to taxonomy terms (images through the Taxonomy Image module, for sure, but not files in general). My guess is that there just aren’t enough people who need to do so.

In a recent project, however, I found myself needing just that. The client in question was using a vocabulary of fonts that had to be associated with their respective font files for JavaScript. After beating my head against the problem for awhile, I managed to figure out a solution. Instead of attaching a file directly to the taxonomy term, I assigned the same vocabulary to a new content type to hold the attachment. Here’s how it works:

  1. Go to Administer > Site building > Modules and make sure the core Taxonomy and Upload modules are enabled.
  2. Go to Administer > Content management > Content types and click the link at the bottom to Add a new content type.
  3. Give your new content type an intuitive name (e.g., Font File) and enable attachments under Workflow settings. Configure the other settings as you see fit and hit Save.
  4. Go to Administer > Content management > Taxonomy and edit the vocabulary for which the file attachments are intended (e.g., Fonts). Check the box next to your new content type and click Save.

Great! Now you have a way of associating a term with a file, albeit indirectly through a node. How you use that information will, of course, vary. In my case, the font files needed to be populated into a drop-down list of font choices for use by JavaScript. Here’s how you might go about accessing the attachment from the database:

&lt;?php

// Fetch the file path of the most recently uploaded file attached to a node that shares the given term
$attachment_path = db_result(db_query("

SELECT filepath FROM {files} f JOIN {upload} u ON f.fid = u.fid JOIN {node} n ON u.vid = n.vid JOIN {term_node} tn ON n.vid = tn.vid WHERE n.type = '%s' AND tn.tid = %d ORDER BY f.timestamp DESC LIMIT 1

", $NODE_TYPE_NAME, $TERM_ID));

?&gt;

Of course, the best solution would be to create a custom module to handle all of this. In my case, there simply wasn’t enough time for that. I invite some enterprising developer to invalidate my technique by creating a module that allows file attachments on taxonomy terms. Until then, I hope someone finds my roundabout hack useful.

Selectable Items per Page Hack for Drupal 6 Views

I’m sure regular contributors to Drupal will cringe at what I’m about to show you, but I found it to be a handy trick. Let’s say you’re using the Views module in Drupal 6 and you want a way to dynamically control the number of items listed in a view. In my case, a client I was working for wanted to be able to select the number of products displayed per page.

Reasonable request, right? Unfortunately, Views doesn’t handle it out of the box. After a bit of fiddling, I managed to come up with the following hack. Mind you, I use the term “hack” here literally; you should never edit a module like this if you can avoid it, if only because it makes updates painful later on.

The operative code is in the pre_execute() function on line 1795 of modules/plugins/views_plugin_display.inc. It normally looks like this:

$this-&gt;view-&gt;set_items_per_page($this-&gt;get_option('items_per_page'));

As the name suggests, anything you feed to this function will set the number of items displayed by the view. In my case, I wanted to use a URL variable coupled with a drop-down menu and some jQuery to toggle it, so I changed it like so:

$this-&gt;view-&gt;set_items_per_page((($_GET['items-per-page'] &gt; 0) ? $_GET['items-per-page'] : $this-&gt;get_option('items_per_page')));

Voila! One line of code and you’re off to the races. Type ‘?items-per-page=X’ into the URL (with X being a number, of course) and it should work like a charm. The pagination even follows suit.

For those who want the full solution, here’s the code for the drop-down menu. You’ll need to add it to a view-specific template file. Just follow the pattern to create your own items per page options.

&lt;?php $items_per_page_override = ($_GET['items-per-page'] &gt; 0) ? $_GET['items-per-page'] : 12; ?&gt;
&lt;div id="items-per-page-selector"&gt;&lt;strong&gt;Items per Page:&lt;/strong&gt; &lt;select&gt;
&lt;option value="12"&lt;?php echo ($items_per_page_override == 12) ? ' selected="selected"' : ''; ?&gt;&gt;12&lt;/option&gt;
&lt;option value="18"&lt;?php echo ($items_per_page_override == 18) ? ' selected="selected"' : ''; ?&gt;&gt;18&lt;/option&gt;
&lt;option value="24"&lt;?php echo ($items_per_page_override == 24) ? ' selected="selected"' : ''; ?&gt;&gt;24&lt;/option&gt;
&lt;option value="9999"&lt;?php echo ($items_per_page_override == 9999) ? ' selected="selected"' : ''; ?&gt;&gt;All&lt;/option&gt;
&lt;/select&gt;

And here is the jQuery that controls the behavior of the drop-down menu.

$(document).ready(function(){
$('#items-per-page-selector select').change(function(){
window.location = '?items-per-page=' + $(this).val();
});
});