Translations of this page?:

"You are here" breadcrumb navigation and linking to namespace index pages

Jason Byrne 2005-09-26 04:48

I wanted to organize my wiki into strict namespaces and I wasn't fond of the breadcrumbs that showed the recently visited pages. I was pleased to find it was easy to implement "you are here" style breadcrumbs instead. However, I wanted the breadcrumbs for namespaces to link to a namespace index page.

Example:

start > deserts > ice_cream > vanilla

I wanted the ice_cream link to go to deserts:ice_cream:index instead of just deserts:ice_cream (because I wanted the index page to be in the namespace that it is indexing!).

So I tweaked the inc/template.php and added a few keys to conf/local.php for a bit more flexibility in the breadcrumbs and here's what I came up with…

/conf/local.php

 
$conf['crumbsep'] = ' → ';       // Specifies what separates each breadcrumb
$conf['index'] = 'index';             // Sets the name for the index page
$conf['removeunderscore'] = 1;        // Removes underscore from the displayed breadcrumb links

inc/template.php

Replace your tpl_youarehere() function with this:

 
function tpl_youarehere(){
  global $conf;
  global $ID;
  global $lang;
 
 
  $parts     = explode(':', $ID);
 
  print $lang['breadcrumb'].': ';
 
  // Always show start page
  if ($a_part[0] != $conf['start']) {
	tpl_link(wl($conf['start']), $conf['start'], 'title="'.$conf['start'].'"');	  
  }
 
  $page = '';
  $last = count($parts);
  $count = 1;
 
  foreach ($parts as $part) {
		if ($count != $last || $part != $conf['index']) {
			// Skip start page if already done
			if ($part == $conf['start']) continue;
			print $conf['crumbsep'];
			$page .= $part;
			// Remove underscores
			if ($conf['removeunderscores'] == 1) {
				$part = str_replace('_', ' ', $part);	
			}	
			// Set link variable
			if ($count == $last) $link = $page;
			else $link = "$page:" . $conf['index'];
			// Check if page exists
			if (file_exists(wikiFN($link))) {
				tpl_link(wl($link), $part, 'title="'.$link.'"');
			}
			else {
				// Print link, but mark as not-existing
				tpl_link(wl($link), $part, 'title="'.$link.'" class="wikilink2"');	
			}
			$page .= ':';
		}
		$count++;		
  }
 
}
 

Additional Steps

Going further with the index concept, if there is a link to deserts:ice_cream: (with a colon at the end) by default DokuWiki will strip it off the end. However with one tiny tweak to xhtml.php, it will automatically make it deserts:ice_cream:index.

Add this code after global $ID; in the internallink() function of inc/parser/xhtml.php

// If $id ends in ":" append $conf['index'] to it
        if (eregi(":$", $id)) {
	    	$id = $id.$conf['index'];   
        }

The last step

Activate hierarchical breadcrumbs (function tpl_youarehere()) in lib/tpl/default/main.php or your own template

I plan to look at this hack to see if I can integrate some of it for better namespace index usage. I also I want to create a hack where if someone goes to deserts:ice_cream and a page named deserts:ice_cream does not exist to make it check for deserts:ice_cream:index and redirect them there (if it exists) before sending them to the “topic does not exist yet”.

useheading option

The modified version of the youarehere function proposed here does not take into account the new useheading option. This small modification of the function implements a way of displaying the first header of the page as the pagename otherwise the pagename itself. It's using the p_get_first_heading function (parserutils.php file) and does not parse the namespaces, only the pagename.

Takashi 2006-05-02 14:44

function tpl_youarehere(){
  global $conf;
  global $ID;
  global $lang;
 
 
  $parts     = explode(':', $ID);
 
  print $lang['breadcrumb'].': ';
 
  // Always show start page
  if ($a_part[0] != $conf['start']) {
	tpl_link(wl($conf['start']), $conf['start'], 'title="'.$conf['start'].'"');	  
  }
 
  $page = '';
  $last = count($parts);
  $count = 1;
 
  foreach ($parts as $part) {
		if ($count != $last || $part != $conf['index']) {
			// Skip start page if already done
			if ($part == $conf['start']) continue;
			print $conf['crumbsep'];
 
           $page .= $part;
			// Remove underscores
			if ($conf['removeunderscores'] == 1) {
				$part = str_replace('_', ' ', $part);	
			}	
			// Set link variable
			$name = $part;
           if ($count == $last){
                $link = $page;
               if($conf['useheading']) { 
                    $name = p_get_first_heading($link);
                    if($name == NULL) $name = $part;
               }
			} else {
                $link = "$page:" . $conf['index'];
           }
 
			// Check if page exists
			if (file_exists(wikiFN($link))) {
              tpl_link(wl($link), $name, 'title="'.$link.'"');
			}
			else {
				// Print link, but mark as not-existing
				tpl_link(wl($link), $name, 'title="'.$link.'" class="wikilink2"');	
			}
			$page .= ':';
		}
		$count++;		
  }
}

Capitlizing first letter in breadcrumbs and brevity

Jason Byrne 2006-11-14 23:48

Thanks for that, Takashi. I wanted to have my breadcrumbs not lowercase so I made a change to capitlize the first letter in each (turn it on in conf/local.php). Also I took out the == 1 in the remove underscores part because it's not necessary. So:

function tpl_youarehere(){
  global $conf;
  global $ID;
  global $lang;
 
 
  $parts     = explode(':', $ID);
 
  print $lang['breadcrumb'].': ';
 
  // Always show start page
  if ($a_part[0] != $conf['start']) {
	tpl_link(wl($conf['start']), $conf['start'], 'title="'.$conf['start'].'"');	  
  }
 
  $page = '';
  $last = count($parts);
  $count = 1;
 
  foreach ($parts as $part) {
		if ($count != $last || $part != $conf['index']) {
			// Skip start page if already done
			if ($part == strtolower($conf['start'])) continue;
			print $conf['crumbsep'];
 
           $page .= $part;
			// Remove underscores
			if ($conf['removeunderscores']) {
				$part = str_replace('_', ' ', $part);	
			}	
			// Capitalize name
			if ($conf['capitalizenav']) {
				$part = ucwords($part);	
			}
			// Set link variable
			$name = $part;
           if ($count == $last){
                $link = $page;
               if($conf['useheading']) { 
                    $name = p_get_first_heading($link);
                    if($name == NULL) $name = $part;
               }
			} else {
                $link = "$page:" . $conf['index'];
           }
 
			// Check if page exists
			if (file_exists(wikiFN($link))) {
              tpl_link(wl($link), $name, 'title="'.$link.'"');
			}
			else {
				// Print link, but mark as not-existing
				tpl_link(wl($link), $name, 'title="'.$link.'" class="wikilink2"');	
			}
			$page .= ':';
		}
		$count++;		
  }
}

Commments

This modification is perfect. Way more usable than the standard “you are here”-function. Hope the changes become part of the core. — Andreas 2006-06-14 18:22

Another version for namespace-based sites

Minor changes to make the tip compatible with dokuwiki-rc2007-05-24

Thanos Massias 2007-06-15 08:54

Given a current page with the path:

:a:b:c:d

and

$conf['start'] = 'index';

the levels of youarehere are (in order of preference):

  1. :index
  2. :a:index or :a or skipped
  3. :a:b:index or :a:b or skipped
  4. :a:b:c:index or :a:b:c or skipped
  5. :a:b:c:d

The useheading option is also taken into account.

function tpl_youarehere($sep=' » '){
  global $conf;
  global $ID;
  global $lang;
 
  // check if enabled
  if(!$conf['youarehere']) return false;
 
  if ($conf['sepyouarehere']){
    $sep = $conf['sepyouarehere'];
  }
 
  $parts     = explode(':', $ID);
 
  print $lang['youarehere'].': ';
 
  //always print the startpage
  if( $a_part[0] != $conf['start']){
    if($conf['useheading']){
      $pageName = p_get_first_heading($conf['start']);
    }else{
      $pageName = $conf['start'];
    }
    tpl_link(wl($conf['start']),$pageName,'title="'.$pageName.'"');
  }
 
  $page = '';
  $printsepyouarehere = "T";
  $countarray = 0;
  $countarraymax = count($parts);
  foreach ($parts as $part){
    $countarray++;
 
    // Skip startpage if already done
    if ($part == $conf['start']) continue;
 
    if($printsepyouarehere == "T"){
      print " ".$sep." ";
    }
    $printsepyouarehere = "T";
    $page .= $part;
    $pageindex = $page.':'.$conf['start'];
    if(file_exists(wikiFN($pageindex))){
      if($conf['useheading']){
        $pageName = p_get_first_heading($pageindex);
        $partName = $pageName;
      }else{
        $pageName = $pageindex;
        $partName = $part;
      }
      tpl_link(wl($pageindex),$partName,'title="'.$pageName.'"');
    }else{
      if(file_exists(wikiFN($page))){
        if($conf['useheading']){
          $pageName = p_get_first_heading($page);
          $partName = $pageName;
        }else{
          $pageName = $page;
          $partName = $part;
        }
        if ('X'.$pageName == 'X') {
          $pageName = $page;
          $partName = $part;
        }
        tpl_link(wl($page),$partName,'title="'.$pageName.'"');
      }else{
        if ($countarray == $countarraymax){
          // Print the link, but mark as not-existing, as for other non-existing links
          tpl_link(wl($pageindex),$part,'title="'.$pageindex.'" class="wikilink2"');
        }else{
          $printsepyouarehere = "F";
        }
      }
    }
    $page .= ':';
  }
}

If you set

$conf['sepyouarehere']

it will override the youarehere separator hardcoded above.

Thanos Massias 2006-06-14 19:11

You can see this code in action at http://www.kapagroup.gr/ (the page is in Greek - sorry, but I currently have no publicly available example in English).

Most pages have a path that contains index files at each level. The :news namespace, however is different: There is a :news:index but no :news:2006:index or :news:2006:05:index pages. Additionaly there are no :news:2006 or :news:2006:05 pages. I want to just hide those namespaces from the youarehere path.

You can see the result in this case at: http://www.kapagroup.gr/news/2006/01/01/index

You can also see what happens when you specify a non-existing page in the URL here: http://www.kapagroup.gr/does_not_exist. Notice that does_not_exist in the youarehere path but the link points to …:does_not_exist:index (this is the intended behaviour). This is the intended behaviour as I want a namespace-based site where each namespace (except in special cases) has an index page. Clicking on that link gets me to the canonical namespace plus index page that should be created. The same also happens when searching for a term: http://www.kapagroup.gr/?do=search&id=search_term.

However http://www.kapagroup.gr/does_not_exist/does_not_exist_either doesn't append to the youarehere path. This is also intentional as I don't want to skip creating intermediate index pages.

PS: I had to move this section to the bottom of the page as I realised that the positive user comments in the Comments section above might appear to be for it - well they ain't.

Thanos Massias 2006-06-15 02:44

Integration with Basic Multilanguage Support for local.php

The solution suggested by Thanos Massias above almost perfectly matches my needs.

If I additionally replace

        // Skip startpage if already done
        if ($part == $conf['start']) continue;

with

        // Skip startpage if already done
        if ($part == $conf['start'] || $ID == $conf['start'] ) continue;

in his code, when his solution is even compatible with the Basic Multilanguage Support for local.php.

Clemens Ender 2006-07-11 15:51

Another simple way to have index link for namespaces in the youarehere section

Michael Hundred 2006-08-23 15:06

It works this way. When it writes a link for the youarehere section, it checks if there is the page. If the check fails it looks for a $conf['start'] page for that namespace. If there is an index it writes the link for that page (also using the heading option if enabled).
I've only added the $page_started variable for the namespace index and an if for the check.

Just replace the tpl_youarehere() function with this one:

function tpl_youarehere(){
  global $conf;
  global $ID;
  global $lang;
 
  //check if enabled
  if(!$conf['youarehere']) return;
 
  $parts     = explode(':', $ID);
 
  print $lang['youarehere'].': ';
 
  //always print the startpage
  if( $a_part[0] != $conf['start']){
    if($conf['useheading']){
      $pageName = p_get_first_heading($conf['start']);
    }else{
      $pageName = $conf['start'];
    }
    tpl_link(wl($conf['start']),$pageName,'title="'.$pageName.'"');
  }
 
  $page = '';
  foreach ($parts as $part){
        // Skip startpage if already done
        if ($part == $conf['start']) continue;
 
          print ' » ';
    $page .= $part;
    $page_started=$page;
 
    if(!file_exists(wikiFN($page))&&(file_exists(wikiFN($page.':'.$conf['start'])))){
		$page_started.=':'.$conf['start'];
    }
 
    if(file_exists(wikiFN($page_started))){
      if($conf['useheading']){
        $pageName = p_get_first_heading($page_started);
        $partName = $pageName;
      }else{
        $pageName = $page_started;
        $partName = $part;
      }
      tpl_link(wl($page_started),$partName,'title="'.$pageName.'"');
    }else{
      // Print the link, but mark as not-existing, as for other non-existing links
      tpl_link(wl($page_started),$part,'title="'.$page_started.'" class="wikilink2"');
      //print $page;
    }
 
    $page .= ':';
  }
}
 
wiki/tips/breadcrumb_namespace_index_links.txt · Last modified: 2007/06/15 11:51 by 194.219.69.110
 
Imprint Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
WikiForumIRCBugsTranslate