Simple History trail for wikka
The following code is a simple history trails feature (JavaWoman informed me that "breadcrumbs" are strictly for heirarchical systems & since wiki's are "flat" calling it a "breadcrumb" feature is inappropriate) that can be added to the header.php code to provide a linear history of the last few previously visited pages in the wiki. It only requires a single field added to the users database (add a field called "recentpages" set as type TINYTEXT and set it so it can be null (which is the default)) and it seems to work like a charm. I was inspired by the trail feature at coocoo wakka, but wrote this from scratch.
add the following code to your header.php file near the bottom (immediately before the last "?>").
// WikiTrails code V1.1a copyright by G. M. Bowen & Andrew Somerville, 2005.
// Version1.1a has a minor code change (as suggested here) so that non-wikiname pages were linked properly
// Prepared for a SSHRC funded research project. Licensed under GPL.
// Please keep attributions if distributing code.
if ($user = $this->GetUser())
if (str_word_count($newstring) > 6) {
$newstring = trim(strstr($newstring, " "));
}
$newstring .= " ";
$this->query("UPDATE ".$this->config['table_prefix']."users SET recentpages = '$newstring' WHERE name='$username' ");
// Add trails to printout
$recent = $this->LoadSingle("SELECT recentpages FROM ".$this->config["table_prefix"]."users WHERE name='".$username."'");
######
# Section rewritten by andrew.
$page_names = Array();
# Parse string at spaces, into an array.
$this_pagename = strtok(trim($recent[recentpages]), " ");
while ($this_pagename) {
array_push($page_names,$this_pagename);
$this_pagename = strtok(" ");
}
# Get rid of duplicates.
$page_names = array_unique($page_names);
# Create the trail by walking through the array of page names.
$separator = "";
$page_trail = "";
foreach ($page_names as $this_pagename) {
$page_trail .= $separator."[[".$this_pagename."]]";
$separator = "-->";
}
# Print the trail.
echo "<br /><small><b>Trail:</b> ".$this->format($page_trail)."</small>";
#######
}
//FINISH breadcrumb code
// Version1.1a has a minor code change (as suggested here) so that non-wikiname pages were linked properly
// Prepared for a SSHRC funded research project. Licensed under GPL.
// Please keep attributions if distributing code.
if ($user = $this->GetUser())
if (str_word_count($newstring) > 6) {
$newstring = trim(strstr($newstring, " "));
}
$newstring .= " ";
$this->query("UPDATE ".$this->config['table_prefix']."users SET recentpages = '$newstring' WHERE name='$username' ");
// Add trails to printout
$recent = $this->LoadSingle("SELECT recentpages FROM ".$this->config["table_prefix"]."users WHERE name='".$username."'");
######
# Section rewritten by andrew.
$page_names = Array();
# Parse string at spaces, into an array.
$this_pagename = strtok(trim($recent[recentpages]), " ");
while ($this_pagename) {
array_push($page_names,$this_pagename);
$this_pagename = strtok(" ");
}
# Get rid of duplicates.
$page_names = array_unique($page_names);
# Create the trail by walking through the array of page names.
$separator = "";
$page_trail = "";
foreach ($page_names as $this_pagename) {
$page_trail .= $separator."[[".$this_pagename."]]";
$separator = "-->";
}
# Print the trail.
echo "<br /><small><b>Trail:</b> ".$this->format($page_trail)."</small>";
#######
}
//FINISH breadcrumb code
If you want the list of previously visited pages to be greater or lesser change the "6" value.
Hope this meets your needs folks. If you find ways of making the code more efficient (and that is certainly possible), then please feel free to update it.
Version V1.1 fixes search and replace issues. Problem was that if you were at the page AndrEw and you also had a page AndrewsPage then when you moved around sooner or later you'd get sPage. That problem is now solved.
Added by RolandStens
I have created a version that uses the $_SESSION variable, this makes it a bit more usable since it is not dependent on a user being logged in or not.
My persistance in calling this bread crumbs is hopefully no cause for major discussion. I hope people find this useful.
- Updated the code so now it behaves a bit better and incorporates Ian's comment below.
- You can see this in operation here RolandStens
<?php
// WikiTrails code V2.1 based on copyrighted code by G. M. Bowen & Andrew Somerville, 2005.
// Version 2 stores the crumbs in the $_SESSION variable. This makes this feature usable for all users.
// Originally Prepared for a SSHRC funded research project extended by Roland Stens, 2006. Licensed under GPL.
// Please keep attributions if distributing code.
# Define the maximum breadcrumbs shown.
define("MAX_CRUMBS", 5);
$crumbs=Array();
# Just get the PageTage, no use in doing that more times than 1
$PageTag=$this->GetPageTag();
# Find out if the breadcrumbs were already stored.
if (!isset($_SESSION['breadcrumbs'])) {
# Not stored yet, so set the current page name in the crumbs array.
$crumbs[0]=$PageTag;
} else {
# The crumbs are already stored, so get them and put them in the crumbs array.
$crumbs=$_SESSION['breadcrumbs'];
# Test for the maximum amount of crumbs and if the last pagetag is not
# the same as the last stored tag. If it is a duplicate we'll get rid of it later.
if (count($crumbs) >= MAX_CRUMBS and $PageTag != $crumbs[MAX_CRUMBS - 1])
{
# Drop the first element in the crumbs array.
array_shift($crumbs);
# Add the new page name to the last position in the array.
$crumbs[MAX_CRUMBS - 1]= $PageTag;
}
else
{
# Not at the maximum yet, then just add to page to the end of the array.
$crumbs[count($crumbs)]= $PageTag;
}
}
# Get rid of duplicates, but only if they are in subsequent array locations.
$count=1;
$temp = Array();
$target= Array();
# Only do this, if you have 3 or more entries in the array
if (count($crumbs) > 2) {
while ($count <= (count($crumbs) - 1))
{
$temp[$count - 1] = $crumbs[$count - 1];
$temp[$count] = $crumbs[$count];
$temp = array_unique($temp);
$target= $target + $temp;
$temp = "";
$count++;
}
$crumbs = $target;
}
else {
$crumbs = array_unique($crumbs);
}
# Save the breadcrumbs.
$_SESSION['breadcrumbs'] = $crumbs;
# Create the trail by walking through the array of page names.
$separator = "";
$page_trail = "";
foreach ($crumbs as $this_crumb) {
$page_trail .= $separator."[[".$this_crumb."]]";
$separator = "-->";
}
# Print the trail.
echo "<b>Trail: </b>".$this->format($page_trail)."<hr /><br />";
#######
//FINISH breadcrumb code
?>
// WikiTrails code V2.1 based on copyrighted code by G. M. Bowen & Andrew Somerville, 2005.
// Version 2 stores the crumbs in the $_SESSION variable. This makes this feature usable for all users.
// Originally Prepared for a SSHRC funded research project extended by Roland Stens, 2006. Licensed under GPL.
// Please keep attributions if distributing code.
# Define the maximum breadcrumbs shown.
define("MAX_CRUMBS", 5);
$crumbs=Array();
# Just get the PageTage, no use in doing that more times than 1
$PageTag=$this->GetPageTag();
# Find out if the breadcrumbs were already stored.
if (!isset($_SESSION['breadcrumbs'])) {
# Not stored yet, so set the current page name in the crumbs array.
$crumbs[0]=$PageTag;
} else {
# The crumbs are already stored, so get them and put them in the crumbs array.
$crumbs=$_SESSION['breadcrumbs'];
# Test for the maximum amount of crumbs and if the last pagetag is not
# the same as the last stored tag. If it is a duplicate we'll get rid of it later.
if (count($crumbs) >= MAX_CRUMBS and $PageTag != $crumbs[MAX_CRUMBS - 1])
{
# Drop the first element in the crumbs array.
array_shift($crumbs);
# Add the new page name to the last position in the array.
$crumbs[MAX_CRUMBS - 1]= $PageTag;
}
else
{
# Not at the maximum yet, then just add to page to the end of the array.
$crumbs[count($crumbs)]= $PageTag;
}
}
# Get rid of duplicates, but only if they are in subsequent array locations.
$count=1;
$temp = Array();
$target= Array();
# Only do this, if you have 3 or more entries in the array
if (count($crumbs) > 2) {
while ($count <= (count($crumbs) - 1))
{
$temp[$count - 1] = $crumbs[$count - 1];
$temp[$count] = $crumbs[$count];
$temp = array_unique($temp);
$target= $target + $temp;
$temp = "";
$count++;
}
$crumbs = $target;
}
else {
$crumbs = array_unique($crumbs);
}
# Save the breadcrumbs.
$_SESSION['breadcrumbs'] = $crumbs;
# Create the trail by walking through the array of page names.
$separator = "";
$page_trail = "";
foreach ($crumbs as $this_crumb) {
$page_trail .= $separator."[[".$this_crumb."]]";
$separator = "-->";
}
# Print the trail.
echo "<b>Trail: </b>".$this->format($page_trail)."<hr /><br />";
#######
//FINISH breadcrumb code
?>
- After implementing this one of my installations I felt that populating this with four copies of the same page when editing was less useful. I made a modification to only add the new page if it was different from the previous one,
- after the line:- $crumbs=$_SESSION['breadcrumbs'];
- add
#only add breadcrumb if new page is different
if ($crumbs[count($crumbs)-1] != $this->GetPageTag() ) {
#to enclose the if / else clause following it
}
- which feels psychological correct (if not strictly accurate) IanHayhurst
CategoryUserContributions
- you could use $newstring instead of $recent. That would save a database-call.
- just wondering why you addd spaces the the string and remove them? ( $newstring = trim($newstring).' '.$this->GetPageTag()." "; and $newstring .= " ";)
- if you put the code a little bit "higher" in the header : there is a check if the user is logged-in before the menu is print. Would save you from doing this.
- Great work.
What we have here is not that, but instead is a "history" feature. Very nice in itself (I've nothing against that!), but to avoid confusion it should not be called "breadcrumbs" and it it should not look like a breadcrumb is generally displayed.
@Nils. The trim, as far as I can tell, removes spaces from the beginning and end, and then adds a space to the end. Getting rid of space(s) at the beginning was necessary, but the one at the end was required so when a new page was added on there was a separation.
-- mike
Maybe we can make a little core method to generate a list with a given id from an array - this seems to to be more generally useful.
agreed, simple and useful.
$page_trail .= $separator.$this_pagename;
to
$page_trail .= $separator."[[".$this_pagename."]]";
best,
Ton Zijlstra (http://www.zylstra.org/blog/)
I was getting favicon.ico in my trails.
I fixed this by adding an if statement that checks if it should add it to the trail:
if ($this->GetPageTag() != 'favicon.ico')
$newstring = trim($newstring).' '.$this->GetPageTag()." ";
instead of just:
$newstring = trim($newstring).' '.$this->GetPageTag()." ";
GmBowen: Your mybuddies feature sounds interesting and useful for your project. It seems like it would also be very usefull in a company setting where teams of people are contributing to a large wiki so that they could keep track of the parts others in their team are looking at. Maybe a feature to see which documents their teammates have last edited would be best for that scenario.
Thanks!
code appended to the page
# Get rid of duplicates.
$page_names = array_unique($page_names);
That would take care of this problem is a somewhat easier way. I took that out because I had some issues with it. My code is not perfect (yet) since it behaves a bit erratically when editing pages and such (as you found out). I'll post my refinements as soon as I figure out how to catch some of these problems.
I'll have to play with this a bit more.
Thanks for the feedback.
In short it comes down to that we are only concerned about duplication if it occurs in consequetive crumbs. The array_unique function gets rid of all duplication breaking the logical flow of the crumbs.
You can see this in operation on http://stens.ca/kb