Last updated 7 November 2006. Created on 7 November 2006.
Edited by ceardach. Log in to edit this page.

There are just times when it's easier for me to structure the site by path alias, and I'd like my breadcrumbs to reflect that. Here's a script that will read what your path alias is, and create breadcrumbs reflecting that. It will check to see if the path is related to a taxonomy or node, and return the proper title. If there isn't a path or node (such as pathauto created indexes), then it will just list the word or words as the title.

Place this in your template.php

function url_breadcrumbs() {

  function get_crumb($lvl){

    $uri_request_id = $_SERVER['REQUEST_URI'];
    $urlexplode = explode("?", $uri_request_id);
    $url = explode("/",$urlexplode[0]);

    if($url[$lvl]){
      if($lvl > 1) {
        $var = array_keys($url);
        foreach($var as $vars){
          if($vars == 1){
            $urlpathpeice .= $url[$vars];
          }
          if($vars <= $lvl && $vars > 1){
            $urlpathpeice .= '/'.$url[$vars];
          }
        }
        $urlpathalias = $urlpathpeice;
      } elseif ($lvl == 1) {
        $urlpathalias = $url[$lvl];
      }
      $urlsystem = drupal_lookup_path('source', $urlpathalias);
      $urlsystemexplode = explode("/", $urlsystem);
      $urltype = $urlsystemexplode[0];

      if($urltype == "taxonomy"){
        $term = taxonomy_get_term($urlsystemexplode[2]);
        if($url[$lvl+1]){
          return  ' >> name.'">'.$term->name.'';
        } else {
          return  ' >> '.$term->name.'';
        }
      } elseif($urltype == "node"){
        $node = node_load($urlsystemexplode[1]);
        if($url[$lvl+1]){
          return  ' >> '.$node->title.'';
        } else {
          return  ' >> '.$node->title;
        }
      } else {
        $urltitleexplode = explode("-", $url[$lvl]);
        $words = array_keys($urltitleexplode);
        foreach($words as $word){
          $urltitle .= ''.ucwords($urltitleexplode[$word]).' ';
        }
        if($url[$lvl+1]) {
          return  ' >> '.$urltitle.'';
        } else {
          return  ' >> '.$urltitle.'';
        }
      }
    }
  }

  function get_crumb_all() {
    $uri_request_id = $_SERVER['REQUEST_URI'];
    $urlexplode = explode("?", $uri_request_id);
    $url = explode("/",$urlexplode[0]);
 
    $numbs = array_keys($url);
    foreach($numbs as $numb) {
      $crumbs .= get_crumb($numb);
    }
  return $crumbs;
  }

  $output .= '';

return $output;
}

then, wherever you want the breadcrumbs, such as page.tpl.php

print url_breadcrumbs();

This hasn't been tested extensively. It works for the one site I needed it for.

I'm not really a coder, so please excuse any strangeness, this is about all I know.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

micheleannj’s picture

This worked for me, but you have to have 3 different functions, not two functions wrapped in another...

get crumb { [as above] }
get_all_crumb{ [as above] }
url_breadcrumbs{

$output .= '

';

return $output;
}

Note that this seems to disable the normal print $breadcrumb for some reason (if anyone knows why or a work-around that would be great...)
Thanks!

porelrio’s picture

majnoona's mod worked for me in 5.2
I added a trim($urltitle) to take out the trailing whitespace.

Here is the full code to add to your template.php:

function get_crumb($lvl) {
	$uri_request_id = $_SERVER['REQUEST_URI'];
	$urlexplode = explode("?", $uri_request_id);
	$url = explode("/",$urlexplode[0]);
	
	if($url[$lvl]){
	  if($lvl > 1) {
		$var = array_keys($url);
		foreach($var as $vars){
		  if($vars == 1){
			$urlpathpeice .= $url[$vars];
		  }
		  if($vars <= $lvl && $vars > 1){
			$urlpathpeice .= '/'.$url[$vars];
		  }
		}
		$urlpathalias = $urlpathpeice;
	  } elseif ($lvl == 1) {
		$urlpathalias = $url[$lvl];
	  }
	  $urlsystem = drupal_lookup_path('source', $urlpathalias);
	  $urlsystemexplode = explode("/", $urlsystem);
	  $urltype = $urlsystemexplode[0];
	
	  if($urltype == "taxonomy"){
		$term = taxonomy_get_term($urlsystemexplode[2]);
		if($url[$lvl+1]){
		  return  ' » name.'">'.$term->name.'';
		} else {
		  return  ' » '.$term->name.'';
		}
	  } elseif($urltype == "node"){
		$node = node_load($urlsystemexplode[1]);
		if($url[$lvl+1]){
		  return  ' » '.$node->title.'';
		} else {
		  return  ' » '.$node->title;
		}
	  } else {
		$urltitleexplode = explode("-", $url[$lvl]);
		$words = array_keys($urltitleexplode);
		foreach($words as $word){
		  $urltitle .= ''.ucwords($urltitleexplode[$word]).' ';
		}
		
		// Removes trailing whitespace
		$urltitle = trim($urltitle);
		if($url[$lvl+1]) {
		  return  ' » '.$urltitle.'';
		} else {
		  return  ' » '.$urltitle.'';
		}
	  }
	}
}

function get_crumb_all() {
	$uri_request_id = $_SERVER['REQUEST_URI'];
	$urlexplode = explode("?", $uri_request_id);
	$url = explode("/",$urlexplode[0]);
	
	$numbs = array_keys($url);
	foreach($numbs as $numb) {
	  $crumbs .= get_crumb($numb);
	}
	return $crumbs;
}

function url_breadcrumbs() {
	$output .= '';
	$output .= 'Home';
	$output .= get_crumb_all();
	$output .= '';
	
	return $output;
}
vthirteen’s picture

this code is useless if you have an internationalized drupal and/or your drual is running in a subdirectory. in these 2 cases the breadcrumb will be something like:

"Home > drupalsubfolder > [dir]"
or
"Home > es > [dir]"

eaposztrof’s picture

u can hide the "Home" from the frontpage, just upgrade this section in template.php:

function get_crumb_all() {
    $uri_request_id = $_SERVER['REQUEST_URI'];
    $urlexplode = explode("?", $uri_request_id);
    $url = explode("/",$urlexplode[0]);
    $numbs = array_keys($url);
    foreach($numbs as $numb) {
      $crumbs .= get_crumb($numb);
    }
	if ($crumbs){
	    echo '<a href="/" title="Home">Home</a>';
	}
    return $crumbs;
}

http://eaposztrof.com/drupal | save the planet, kill yourself!

vthirteen’s picture

thank you, but the problem is with the i18n suffix (e.g. "en", "fr", etc.) and the subfolder that are displayed in the URL and hence in the breadcrumbs. i'm pretty sure this can be solved through some php function, but i don't know how. thank you for your help.

ncy’s picture

modified the code ... i'm working in Drupal 6.1 and the way i got around the subfolders problem was using the base_path() function, which returns the path of the Drupal install (which would be the path to the subfolder). i don't know what base_path() returns in an international install, so if somebody can post about that, it'd be great.

i added the argument $breadcrumb (just pass in the $breadcrumb var when you call url_breadcrumb in page.tpl.php). i commented in the code about how to remove "Home" and the current page's title, if that's what you want. let me know if this works ok or could be better :) hope it helps.

<?php
function url_breadcrumb($breadcrumb) {
    $url = path_alias_array();

    // On admin pages, use the default breadcrumb. But I prefer having the
    // title of the current page display as well.  So I remove the '</div>'
    // tag from the original breadcrumb with substr() and add in the title with 
    // drupal_get_title().
    if ($url[0] == 'admin')
        return substr($breadcrumb, 0, -6) . ' &raquo; <strong>' . drupal_get_title() . '</strong></div>';

    $output .= '<div class="breadcrumb">';

    // Remove this line if you don't like the Home link.  You'll need to adjust 
    // the code below too, to not display ">>" (&raquo;) at the start of the 
    // breadcrumb
    $output .= '<a href="' . base_path() . '" title="Home">Home</a>';

    $output .= get_crumb_all();
    $output .= '</div>';

    return $output;
}

// Extract the URL path alias from the URI
function path_alias_array() {

    $uri_request_id = $_SERVER['REQUEST_URI'];
    $urlexplode = explode("?", $uri_request_id);

    if (base_path() != '/') {
        $urlfinal = explode(base_path(), $urlexplode[0]);
        $url = explode("/", $urlfinal[1]);
    }
    else {
        $url = explode("/", $urlexplode[0]);
    }

    return $url;
}

// Get full breadcrumb
function get_crumb_all() {
    $url = path_alias_array();

    // Construct each piece of the breadcrumb
    $numbs = array_keys($url);
    foreach ($numbs as $numb) {
        $crumbs .= get_crumb($numb);
    }
    return $crumbs;
}

// Get breadcrumb piece
function get_crumb($lvl){
    $url = path_alias_array();

    // Reconstruct path alias as string
    for ($i = 0; $i < $lvl+1; $i++) {
        $urlpathalias .= $url[$i];
        if ($i != $lvl)
            $urlpathalias .= '/';
    }
    $urlpathalias = str_replace('%20', ' ', $urlpathalias);

    // If Drupal install is not in a subdir, we need to remove extra '/'
    if ($urlpathalias[0] == '/')
        $urlpathalias = substr($urlpathalias, 1);

    // If at Home, return now so we don't append the '>>'
    if ($urlpathalias == '')
        return;

    // It is assumed that all paths are URL path aliases, so if you go to a 
    // page without a path alias, the breadcrumb will not display correctly
    $urlsystem = drupal_lookup_path('source', $urlpathalias);
    $urlsystemexplode = explode("/", $urlsystem);
    $urltype = $urlsystemexplode[0];

    $crumbpiece = ' &raquo; ';

    // Uncomment this if you remove the Home crumb above
    // if ($lvl == 1)
    //     $crumbpiece = ' ';

    if ($urltype == "taxonomy") {
        $term = taxonomy_get_term($urlsystemexplode[2]);
        if ($lvl == count($url)-1) {
            // Set to '' if you don't want to display current page's title
            $crumbpiece =  $crumbpiece . ' <strong>'.$term->name.'</strong>';
        }
        else {
            $crumbpiece =  $crumbpiece . ' <a href="' . base_path() .$urlpathalias.'" title="'.$term->name.'">'.$term->name.'</a>';
        }
    }
    elseif ($urltype == "node") {
        $node = node_load($urlsystemexplode[1]);
        if ($lvl == count($url)-1) {
            // Set to '' if you don't want to display current page's title
            $crumbpiece =  $crumbpiece . ' <strong>'.$node->title.'</strong>';
        }
        else {
            $crumbpiece =  $crumbpiece . ' <a href="' . base_path() . $urlpathalias.'">'.$node->title.'</a>';
        }
    }
    else {
        $urltitleexplode = explode("-", $url[$lvl]);
        $words = array_keys($urltitleexplode);
        foreach ($words as $word){
            $urltitle .= ''.ucwords($urltitleexplode[$word]).' ';
        }
        if ($lvl == count($url)-1) {
            // Set to '' if you don't want to display current page's title
            $crumbpiece =  $crumbpiece . ' <strong>'.$urltitle.'</strong>';
        }
        else {
            $crumbpiece =  $crumbpiece . ' <a href="' . base_path() .$urlpathalias.'" title="'.$urltitle.'">'.$urltitle.'</a>';
        }
    }

    // Deal with underscores before returning
    $crumbpiece = str_replace('_', ' ', $crumbpiece);
    return ucwords($crumbpiece);
}

ncy’s picture

breadcrumbs from Menu path http://drupal.org/project/menu_breadcrumb . this was exactly what i was looking for in the first place. for Drupal 6 only ...

Trunkhorn’s picture

This was such an awesome share... for anyone else who wants to use the above code but sees it not work, keep in mind that this person wrote the function url_breadcrumbs without the "s", so you would instead need:

<?php print url_breadcrumb(); ?>

In your page.tpl instead of breadcrumb"s".

lelizondo’s picture

Actually is:

<?php print url_breadcrumb($breadcrumb); ?>

Luis

tomho’s picture

Hey guys, great function here, one thing is that i can't preserve the look of french characters, do you know where i need to make changes?

This is whats happening right now.
Intégration

turns into
Int%C3%A9gration

Thanks

ncy’s picture

it's been awhile since i did anything with international characters. i think it's something to do with utf8_decode() and utf8_encode()? they're PHP functions.

eaflash’s picture

Use @rawurldecode

hampshire’s picture

The code for 6.1 above runs into problems when you have a trailing slash at the end of your address. For example domain.com/level1/level2/ would show a breadcrumb trail of Home > Level1 > Level2 > all of which are links instead of Home > Level1 > Level2 with Level2 being just text.

clint.beacock’s picture

Thanks a lot for putting this up, and I should also thank the original poster.

I needed to create a custom breadcrumb trail using menu-items, node pages, and taxonomy items. I was going to play around with one of the contributed breadcrumb modules, but out of sheer laziness I threw your code in to see how it would do, and it's done exactly what I was after!

Again, thanks to everyone who's taken the time to contribute here!

dquakenbush’s picture

Your snip was very close to what I wanted to do, but not quite.

After reading a ridiculous number of other posts trying to fix both breadcrumbs and menus for node level pages (this trick is generally considered impossible...) I came up with this ugly hack. If someone could roll this into a module, plus figure out how to invoke only on node level pages of certain types I would be happy to buy you a pizza :-)

It figures out where the node should live based on the clean URL, then uses menu_set_location to happily unroll the correct number of menus nested to an arbitrary depth, and posts a complete breadcrumb trail.

Caution: it runs on every single page, needed or not, regardless of type. Untested on taxonomy-centric sites.

Paste this into the bottom of your template.php :


//Node Path/Menu Repair based on pathauto + custom paths
//This should be a module, but I couldn't get it to work that way...
//And it should only work for specific content types, but I couldn't get it to work that way either...

function path2menu($node){

    //Grab the URL
    $uri_request = $_SERVER['REQUEST_URI'];
    $urlexplode = explode("?", $uri_request);
    $url = explode("/", substr($urlexplode[0], 1));  
    //so we have an array of url entities, no parameters, skip the opening slash
    
    //we need to build the breadcrumb such that each entry adds to the one before..
    //so [0] will be "animation", [1] will be "animation/profiles", etc
    //[1] one should not be "profiles" on its own. We do this with $scratch in the loop below.

	//echo $node->type;  //debugging
	//if($node->type == 'artist_profile'){  //content-type filter -- doesn't work without access to $node
				
			
		//Build our faux hook_menu array
			$crumbs = array();  //this will hold our menu items -- 'path', 'title'
			$scratch = ""; //this will hold our slowly growing list
			foreach($url as $item){
				$scratch = $scratch . $item;
				$thistitle = ucfirst(str_replace("-"," ",$item)); //hyphens to spaces, cap first letters. YMMV.
				$thispath = drupal_get_normal_path($scratch);
				$scratch = $scratch . "/";
				$crumbs[] = array ('title' => $thistitle, 'path' => $thispath);
				
				//uncomment to debug
				//echo " title: $thistitle, path: $thispath ";
				
				
				//housekeeping, mostly out of habit.
				$thistitle = "";
				$thispath = "";
			}
		
		
		//Pass it to menu_set_location() to open the menu and write the breadcrumb trail.
			menu_set_location($crumbs);
			
	//} //debugging for content-type if/then -- can't read $node from here, so it doesn't work.
}

path2menu($node);

robert-hartl’s picture

The original version works for me perfect (5.x) - the others don't.
Thanks so much, custom_breadcrumb could not solve the simple problem of right paths and urls.
If You don't want to show "Home" on the frontpage simply solve it by the include in page.tpl.php (if it is not front print url_breadcrumb).

norio’s picture

This is great! Thank you! :)

DiviCreativeMedia’s picture

Here is my simplified version to accomplish this goal. I'm using 6.x and don't know if it will work in earlier versions.

In template.php:

function bcrumb() {
   $bcrumb = '<a href="/">Home</a>&nbsp;&nbsp;>&nbsp;&nbsp;'; // Start of breadcrumb. This creates a leading 'Home' link.
   $dir_url = $_REQUEST['q'];
   $pathArray = explode("/",$dir_url);
   $crumbCount = count($pathArray);
   for($i=0; $i<$crumbCount; $i++)
   {
      $checkPath = "";
      for ($j=0; $j<=$i; $j++)
      {
         $checkPath .= $pathArray[$j];
         if ($j < $i)
            $checkPath .= "/";
      }
      $pathSource = drupal_lookup_path(source, $checkPath);
      if ($pathSource) // If an alias doesn't exist for the current path the crumb is skipped, preventing mid-crumb blanks.
      {
         $nodeStrip = substr($pathSource,5);
         $pageTitle = db_result(db_query("SELECT title FROM node WHERE nid = '$nodeStrip'"));
         if ($i == ($crumbCount-1))
            $bcrumb .= $pageTitle;
         else
            $bcrumb .= '<a href="/' . $checkPath . '">' . $pageTitle . '</a>&nbsp;&nbsp;>&nbsp;&nbsp;';
      }
   }
   print($bcrumb);
   return true;
}

For your .tpl files, wherever you want the breadcrumb to appear: bcrumb();

One big difference in this code is it skips any level that doesn't have an alias. Spacing and capitalizing the word doesn't do any good if clicking the link gets you a page not found.

The site I wrote this for does not use taxonomy, so I have no idea if it will work properly on taxonomy pages.

---------------------------
Divi Creative Media
www.divicreative.com

Trunkhorn’s picture

I'm all taxonomy now, so I'll try it and let you know.

Frederickweiss’s picture

This worked great for me, thank you.

mauritsl’s picture

For 6.x, there is a module which resembles this code, which is Hansel breadcrumbs.

jsmanley’s picture

This code worked perfect for me in drupal 6 with one addition. My menu had views with taxonomy term arguments, some of which had ampersands, so the url would include %2526. I was able to convert them in the link titles by placing the following line of code towards the bottom right after:

foreach ($words as $word){
            $urltitle .= ''.ucwords($urltitleexplode[$word]).' ';
        }

Add:

$urltitle = str_replace('%2526', '&amp;', $urltitle);
Blackout’s picture

Hi,

Thanks a lot to those who contributed! Great thing, easy to add to a site :)

Just changed
$output .= 'Home';
to
if ($_SERVER['REQUEST_URI'] != "/") $output .= 'Home';
so there is no HOME link on the homepage.

Best regards,
BlackoutCK

chazz’s picture

Thank you, was looking to remove it from home