HowTo: Replace node title with a related image
I took over a static site, designed with Dreamweaver. The site design and layout were beautiful, and one of my goals for converting the site to Drupal was to maintain as much of the site's visual appeal as possible. One of the visual elements were sharp graphic titles on each page. And so began my quest to figure out how to replace drupal's text title with these image versions. I tried several methods before coming across the excellent article above (this page's parent), which gave me the following idea (much of the code is lifted directly from that article).
Overview: basic concept
A node on your site has a title, like "Bob's Antiques & Junk", and you want to display the related image file "bobs_antiques_junk.gif" instead of this text title when displaying the node as a page. Furthermore, you want the original title as alt text on the image, and you want "graceful degradation", so the original text title is displayed if the "related image" file does not exist.
What this does is essentially make the Title field of the nodes into an special image selector - if you use a title with an associated image, the image will appear, otherwise, the text title will appear - sweet!
Requirements:
- You are using a template theme.
- You are not averse to a little php.
All code goes into your template.php file.
NOTE: Ignore the opening and closing PHP tags in here. They are just for display and should not be added to your file.
For background info on template.php and the phptemplae_variables function, see:
- template.php: Overriding other theme functions http://drupal.org/node/11811
- Adding function call to _phptemplate_variables http://drupal.org/node/207841
- HowTo: merge multiple _phptemplate_variables functions http://drupal.org/node/152426
Step 1: convert title to related filename
<?php
// Prepare some general title text for use as a file name.
// Remove special HTML characters, trim whitespace, convert to lower-case
// repace spaces with underscores.
function clean_title($string)
{
$cleanString = htmlspecialchars_decode( strtolower(trim($string)), ENT_QUOTES );
$cleanString = str_replace(array("& ", "'"), '', $cleanString);
return str_replace(' ', '_', $cleanString );;
}
?>This handy little function will take a title, like "Bob's Antiques & Junk" and convert it to a nice base filename: "bobs_antique_junk". Since Drupal will convert quotes and ampersands to "special characters" (e.g., $#039; or $amp;), it strips those out first. Then does a simple replace to get rid of apostrophe's and ampersands - common in titles. Finally, it replaces remaining spaces with underscores.
This function can be customized to convert titles to filenames however you see fit. Depending on the titles on your site, you may want to extend the substitutions made here. For example, use a regex to match and replace patterns (e.g., preg_replace("/[^a-zA-Z0-9]/", "", $string) ) - this is a little slower, but more general purpose.
Step 2: making the substitution - code snippets
We need both the file system path (to check if the file exists) and the URL (to form the image tag) for the title image. Note: substitute the correct extension and path to your title images - mine are '.gif' files that live in "files/images/titles".
<?php
// convert title to suitable filename and derive both file system path and URL.
$titleFile = clean_title($vars['title']) . '.gif';
$titleImage = base_path() . "files/images/titles/" . $titleFile;
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
?>Only perform the substitution if the "related image" can be found. Use $vars['title'] as the alt text for the image tag, and then put the image tag back in to $vars['title'].
<?php
// Determine if a suitable replacement image for title can be found, and make substitution.
if ( file_exists($titlePath) ) {
$newTitle = '<img alt=\'' . $vars['title'] .'\' src=\'' . $titleURL .'\' />';
$vars['title'] = $newTitle;
}
}
?>A few refinements:
Restrict application of the substitution - see the parent article, which explains this nicely.
<?php
// Substitute title only for nodes...
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
// ... of one of the listed types.
if (in_array($node->type, array('page'))) {
// convert title to suitable filename and derive both file system path and URL.
...
?>Save original title text for use in head and breadcrumb.
<?php
$vars['breadcrumb_title'] = $vars['title'];
$vars['head_title'] = $vars['title'];
?>Step 3: putting it all together
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page':
// substitute node title with an image, if a suitable replacement can be found.
// save original title text for use in head and breadcrumb.
$vars['breadcrumb_title'] = $vars['title'];
$vars['head_title'] = $vars['title'];
// Substitute title only for nodes...
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1)); // (expensive, unless arg(1) is already loaded, which is should be at this point.)
// ... of one of the listed types - add node types to process to the array.
if (in_array($node->type, array('page'))) {
// convert title to suitable filename and derive both file system path and URL.
$titleFile = clean_title($vars['title']) . '.gif';
$titleImage = base_path() . "files/images/titles/" . $titleFile;
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
// $vars['title'] = $titleURL; // DEBUG - see what's being produced
// Determine if a suitable replacement image for title can be found, and make substitution.
if ( file_exists($titlePath) ) {
$newTitle = '<img alt=\'' . $vars['title'] .'\' src=\'' . $titleURL .'\' />';
$vars['title'] = $newTitle;
}
}
}
break;
}
return $vars;
}
?>I hope this helps someone - and if anyone with better PHP skills and Drupal knowledge than I (which means most ;-), has some suggestions for improving this script, please let me know.

Great code! I modified slighly for version 6.
This code works great! I made a couple of modifications based on how the preprocessing function are described in the version 6 themes handout.
In template.php:
<?php
// afc/template.php
// Prepare some general title text for use as a file name.
// Remove special HTML characters, trim whitespace, convert to lower-case
// repace spaces with underscores.
function clean_title($string)
{
$replace_chars = array("&", ":", ",", "'");
$cleanString = htmlspecialchars_decode( strtolower(trim($string)), ENT_QUOTES );
$cleanString = str_replace($replace_chars, "", $cleanString);
return str_replace(' ', '_', $cleanString );;
}
function mytheme_preprocess_node(&$variables) {
// substitute node title with an image, if a suitable replacement can be found.
// save original title text for use in head and breadcrumb.
$variables['breadcrumb_title'] = $variables['title'];
$variables['head_title'] = $variables['title'];
// Substitute title only for nodes...
$titleFile = clean_title($variables['title']) . '.png';
$titleImage = base_path() . path_to_theme() . "/images/titles/" . $titleFile;
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
//$variables['title'] = $titleURL; // DEBUG - see what's being produced
// Determine if a suitable replacement image for title can be found, and make substitution.
if ( file_exists($titlePath) ) {
$newTitle = '<img alt="' . $variables['title'] .'" src="' . $titleURL .'" />';
$variables['title'] = $newTitle;
}
}
?>
Can this also work in a view?
This is a nice script and works very well.
I have a teaserlist in a view where I would also like to have the images for the titles.
Is this possible?
I have no idea where to change the script to get that working..
Yes, its possible
This script specifically changes the page title:
<?phpswitch ($hook) {
case 'page':
?>
To change the node titles on a teaser list, you need a similar scheme for the 'node' hook.
Best bet is to encapsulate the replace title function (you can download the code and some instructions to install it here: http://lasqueti.ca/books/design-notes/image-titles )
Then do this in phptemplate_variables():
<?php
switch ($hook) {
case 'page':
/ ...
$vars['text_title'] = $vars['title']; // save off text title.
$vars['title'] = title_to_image($vars['title']);
/...
break;
case 'node':
/...
$vars['text_title'] = $vars['title'];
if ( $vars['teaser'] ) {
$vars['title'] = title_to_image($vars['title']);
}
// ...
?>
You may need to modify your node template a little too - can't recall.
good luck.
Editing the template.php
Editing the template.php script and adding to server makes the site disappear.....any suggestions?
I cut and pasted code from
I cut and pasted code from above and came up with the following:
<?php
/*
Functions for replacing title with image
*/
// Prepare some general title text for use as a file name.
// Remove special HTML characters, trim whitespace, convert to lower-case
// repace spaces with underscores.
function clean_title($string)
{
$cleanString = htmlspecialchars_decode( strtolower(trim($string)), ENT_QUOTES );
$cleanString = str_replace(array("& ", "'"), '', $cleanString);
return str_replace(' ', '_', $cleanString );;
}
function title_to_image($title)
{
$ext = '.gif';
$path = 'files/images/titles/';
// convert title to suitable filename
// and derive the file system path to that imaginary file.
$titleFile = clean_title($title) . $ext;
$titleImage = base_path() . $path . $titleFile;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
// Determine if a suitable replacement image for title can be found,
// and, if so, make substitution with the related URL.
if ( file_exists($titlePath) ) {
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$newTitle = '<img alt=\'' . $title .'\' title=\'' . $title .'\' src=\'' . $titleURL .'\' />';
return $newTitle;
}
else { // no suitable image file could be found - return old title.
return $title;
}
}
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page':
// substitute node title with an image, if a suitable replacement can be found.
// save original title text for use in head and breadcrumb.
$vars['breadcrumb_title'] = $vars['title'];
$vars['head_title'] = $vars['title'];
// Substitute title only for nodes...
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1)); // (expensive, unless arg(1) is already loaded, which is should be at this point.)
// ... of one of the listed types - add node types to process to the array.
if (in_array($node->type, array('page'))) {
// convert title to suitable filename and derive both file system path and URL.
$titleFile = clean_title($vars['title']) . '.gif';
$titleImage = base_path() . "files/images/titles/" . $titleFile;
$titleURL = "http://" . $_SERVER['SERVER_NAME'] . $titleImage;
$titlePath = $_SERVER['DOCUMENT_ROOT'] . $titleImage;
// $vars['title'] = $titleURL; // DEBUG - see what's being produced
// Determine if a suitable replacement image for title can be found, and make substitution.
if ( file_exists($titlePath) ) {
$newTitle = '<img alt=\'' . $vars['title'] .'\' src=\'' . $titleURL .'\' />';
$vars['title'] = $newTitle;
}
}
}
case 'node':
$vars['text_title'] = $vars['title'];
if ( $vars['teaser'] ) {
$vars['title'] = title_to_image($vars['title']);
}
break;
}
return $vars;
}
?>
I put it in template.php and it worked..
$title of a view?
This comes so close to exactly what I'm looking for. Does anyone know how to extend this to views (the title of the view, not the titles of the nodes in the view) and to the contact form at /contact?
It's Still Not Working! What Am I Doing Wrong?
I have taken the code above and placed in my template.php file, but I had no luck.
Is there anything special you need to do in the page.tpl.php file to get it to work correctly?
I do have images to replace the $titles in:
/public_html/files/images/titles/
and in
/public_html/sites/default/files/images/titles/
to make sure that the function can find the images.
Any suggestions to what I am not doing or what I am doing wrong?