Starting from the Cookbook Breadcrumb example, I modified that by adding the following features:
-
Automatically tracks a user history since visiting the homepage. You no longer need to establish the bread crumb list for every view.
-
The breadcrumb name can either be set from either the page title or via a crumb title property.
-
The widget is established in the main layout view. So you don’t need to put the widget in every view. Just set it in the main layout once, and you’ll have breadcrumbs on every page.
-
Will truncate the breadcrumb list if it gets too long.
-
You can exclude certain pages (like the Login page) from showing up in the breadcrumb list.
I’ve only been using Yii for a couple of days, so there might be ways to improve this. Please feel free to share your comments. Enjoy!
components/BreadCrumb.php:
<?php
class BreadCrumb extends CWidget {
public $crumbs = array();
public $newCrumb =array();
public $delimiter = ' &rarr ';
public $hideCrumbsOnHome = true;
public $firstCrumb = array('Home' => array('name' => 'Home', 'url' => array('site/index')));
public $excludeCrumbs = array('Login');
public $crumbs2Show = 3;
public $truncatedCrumb = array('Truncated' => array('name' => '...'));
public function run() {
// Breadcrumbs are a way back to to the homepage so dump
// the crumbs if we find ourselves back on the homepage
$homepageRoutes = array('/index.php','/site/index','/');
if ( in_array($this->newCrumb['url'][0], $homepageRoutes)) {
unset ($_SESSION['crumbs']);
// If desired, don't show the lone Home crumb on
// the homepage
if ($this->hideCrumbsOnHome) {
return;
}
}
// Place the homepgage anchor crumb in the first position
$this->crumbs = $this->firstCrumb;
// Some pages, such as Login, we don't want in the list, so
// let's exclude them
if ( !in_array($this->newCrumb['name'], $this->excludeCrumbs)) {
$newCrumbKey = $this->newCrumb['name'];
// If we have an existing crumb list, check to see whether
// the new crumb is already in the list. If so, dump all the
// crumbs from that crumb position to the end of the list. The
// purpose of this is to keep the list clean of duplicates.
if ( sizeof($_SESSION['crumbs']) > 0 ) {
if ( array_key_exists($newCrumbKey, $_SESSION['crumbs'])) {
$offset = $this->array_offset($_SESSION['crumbs'], $newCrumbKey);
$_SESSION['crumbs'] = array_slice( $_SESSION['crumbs'], 0, $offset, true);
}
}
// Finally add the new crumb to the end of the list
$_SESSION['crumbs'][$newCrumbKey]=$this->newCrumb;
// If we have more crumbs than we want to display, we'll evict the
// oldest crumbs from the list. Plus we'll show a truncated crumb
// so the user has a visual indicator that we are truncating.
if (sizeof($_SESSION['crumbs']) > $this->crumbs2Show ) {
array_shift($_SESSION['crumbs']) ;
$this->crumbs = array_merge($this->crumbs, $this->truncatedCrumb);
}
}
// Ok, we've build the crumb list prefix with the Home crumb and possibly
// the Truncated crumb. Now lets add the user's crumbs.
if ( sizeof($_SESSION['crumbs']) > 0 ) {
$this->crumbs = array_merge($this->crumbs, $_SESSION['crumbs']);
}
// display!
$this->render('breadCrumb');
}
/**
* Find the integer position of the offset key in the array
* @param array $array
* @param string $offset_key
* @return int
*/
public function array_offset($array, $offset_key) {
$offset = 0;
foreach($array as $key=>$val) {
if($key == $offset_key)
return $offset;
$offset++;
}
return -1;
}
}
?>
components/views/breadCrumb.php:
<div id="breadCrumb">
<?php
$lastCrumb = array_pop($this->crumbs);
foreach($this->crumbs as $crumb) {
if(isset($crumb['url']) && !$isLastCrumb) {
echo CHtml::link($crumb['name'], $crumb['url']);
} else {
echo $crumb['name'];
}
echo $this->delimiter;
}
echo $lastCrumb['name'];
?>
</div>
views/layouts/main.php
Note: You can set the breadcrumb title from one of two properties: either the page title property built into CControler or by a bread crumb title property that you will need to add into the relevant controller. Here’s the steps needed to handle each scenario:
- pageTitle:
[list=1]
- In the controller actions, set the page title before rendering like so: $this->setPageTitle(‘Product #1022 Blue Bag with Shoulder Strap’)
[*]crumbTitle: Sometimes, you want the breadcrumb to be shorter or different than the page title. Setting this property will allow for that.
[list=1]
[*]Add the crumbTitle property to the controller class like so: public $crumbTitle;
[*]In the controller’s actions, set the crumbTitle like so: $this->crumbTitle = ‘Product #1022’
[/list]
[/list]
<div id="breadcrumbs">
<?php $this->widget('application.components.BreadCrumb', array(
'newCrumb' =>
array('name' => isset($this->crumbTitle)?$this->crumbTitle:$this->getPageTitle(), 'url' => array($_SERVER['REQUEST_URI']))
)); ?>
</div>