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


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.

<?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
?>




CategoryUserContributions
Comments [Hide comments]
2005-05-11 12:35:17
Very good! I was waiting for this. Thanks a lot.
Comment by NilsLindenberg
2005-05-23 12:19:41
From looking at the code:

- 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.
Comment by JavaWoman
2005-05-23 21:25:56
I feel I should point out again that generally "breadcrumbs" interfaces are used to show the user "where" they are in a *hierarchical* site structure and allo wnavigation within that structure.

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.
Comment by GmBowen
2005-05-24 06:33:03
Oh, okay...obviously I didn't understand the distinction. Well, I was calling it WikiTrails but thought what I used was more appropriate. If you re-name the page I'll hunt around for what I added (basically on one page today & code contributions & on Christian's page) and change the links. A minor update will follow in a week (taking Nils' comments into account and a few other things) when I return from a trip.

@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
Comment by JavaWoman
2005-05-24 09:12:30
Unfortunately we can't do an actual rename yet ... it would be possible to clone the page (you could do that yourself) but that would lose the page history and (more importantly perhaps) the comments. Maybe when we implement a rename handler...
Comment by JavaWoman
2005-05-24 09:16:38
As to the implementation, it would be (structurally) better to generate the content as an unordered list with an appropiate id, and then use CSS to style it.

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.
Comment by DarTar
2005-05-24 09:18:23
> a little core method to generate a list with a given id from an array

agreed, simple and useful.
Comment by zylstra-2.demon.nl
2005-05-28 15:33:59
I have added this code to my wikka install, and it worked well. However some users of the wiki have created pages that don't have WikiNames, in stead they used double [[ ]]. In the trail this results in pagenames that aren't hyperlinks. To counter this I have changed the line where the trail is build from:

$page_trail .= $separator.$this_pagename;

to

$page_trail .= $separator."[[".$this_pagename."]]";

best,

Ton Zijlstra (http://www.zylstra.org/blog/)
Comment by GmBowen
2005-05-29 14:57:09
Hey, thanks Ton. I'd run across this problem myself but hadn't sat down to puzzle out how to solve it....but I'm sure that your solution is more elegant and simple than mine would have been.
Comment by 71.128.254.173
2005-07-26 23:51:01
Thanks for the feature!!
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()." ";
Comment by 71.128.254.173
2005-07-26 23:57:14
is there any way that I can make this work for users who are not logged in?
Comment by GmBowen
2005-07-27 13:52:07
Well, not the way it currently works as it writes to the user table in the database. If it was rewritten to save in a "cookie" on the users machine then you could, but not with the current use of the usertable. You'd have to do this yourself as the the current design best fits my needs.....so that the "mybuddies" feature I developed can list where your friends have been to recently, and that requires that the info is stored in the database & not on your local machine.
Comment by JavaWoman
2005-07-27 20:01:41
Just an idea: instead of using a cookie, the information could also be stored in the session: no need for an extra cookie.
Comment by HypeXR
2005-08-01 09:21:29
So, by "in the session" you are saying that the info could be stored in a session variable, instead of using the database or a cookie?
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.
Comment by GmBowen
2005-08-01 14:48:21
Hi Scott. A more complete description of the context of the mybuddies feature is available in the para at the bottom of VirtualWikiFarm. I'll release the complete package of files soon. I've been away for 2 months doing research and the programmer I'm working with was polishing the final tool set and getting it ready for making available to the wikka community but was hospitalized a month ago thus delaying its release. It should be available soon. Your description of intended use is exactly what the MyTown feature was developed for (originally called VirtualWikiFarm). cheers, Mike Bowen
Comment by 131.202.144.27
2006-01-25 09:17:00
Hey, what a great contribution. Thanks for providing it Roland.
Comment by IanHayhurst
2006-01-30 05:42:07
Top feature Roland !, If you visit a page, edit, store etc then the last 4 entries are (correctly) the same page though psycologically one would expect just the one entry, may be a future enhance ment would to be to ignore consecutive entries for the same page ?
Thanks!
Comment by IanHayhurst
2006-01-30 06:58:43
ok, had a go ... php isn't that scary after all ;-)
code appended to the page
Comment by RolandStens
2006-01-30 17:25:50
Actually the original had the following line:
# 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.
Comment by IanHayhurst
2006-01-31 04:12:30
mmm noticed that after, then thought the order might still be useful ?
Comment by RolandStens
2006-01-31 12:52:08
The order is definitely useful, the eradication of the duplicates definitely breaks this order. That was the main reason why I took it out.
I'll have to play with this a bit more.

Thanks for the feedback.
Comment by RolandStens
2006-01-31 17:46:50
Updated the code (Version 2.1) so now it behaves a bit better and incorporates Ian's comment about the duplication.
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
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki