Tuesday, November 27, 2012

StackExchange and the [tridion] tag

If you use any of the Tridion community resources, you have certainly started using StackOverflow for your Tridion questions (or for your daily dose of questions).

However, we seem to have started abusing the principles of StackOverflow - programming questions - and getting more and more configuration questions.

While, obviously, our community members rush out to try to help, it will probably not be long before someone starts closing off threads that ask no real question, no real programming question, or that are just discussion starters.

The number of open-ended, non-programming questions is annoying (to say the least). Luckily, the people behind StackExchange know very well that not all IT questions are programming questions, so there are other sites that we can use for all your Tridion Software knowledge questions:

- ServerFault
- SuperUser

So, next time you're going to ask on StackOverflow how to configure Session Preview, or how to best design a workflow, please take a minute to consider if this is a programming question, and if this should be in Stack Overflow. Server configuration questions are better suited for ServerFault, while usability questions should go in SuperUser. Simple.

If you're afraid that people may miss it (since most people only monitor Stack Overflow after all), then perhaps shout out on the Tridion Forum too. The MVPs typically pick up on these things quite fast, and the community will continue growing without impacting our generous hosts at SO.

Yes, I also agree that we should have a Tridion-dedicated Stack Exchange site. That's why I committed to this proposal on Area 51, as I am sure you have too.

Saturday, November 24, 2012

How would you do it without Tridion?

I see myself being quoted more & more on the above question, which is one of my favorite answers to most Tridion implementation questions.

So I thought it was time to start putting here some of the questions that made me come up with that answer... Just walk through these questions and - in your mind - answer each with "How would I do it without Tridion?" - you'll find that the answer is almost always exactly the same when you do something with Tridion or without it, which I think is one the greatest strengths of this amazing product. These are real questions that I have been asked (some more often than others) in the past years:
  1. How do I do A/B Testing with Tridion?
  2. How do I configure a reverse proxy for my Tridion website?
  3. How do I integrate comments into my pages?
  4. How do I integrate search into my website?
  5. How do I call a webservice from a template?
  6. How do I check my website performance?
  7. How do I add analytics?
  8. How do I improve my SEO?
  9. How do I add a Javascript or CSS file to my pages?
And I could go on. The fact that I keep getting this type of questions makes me think that there is something fundamentally wrong with the way Tridion is perceived in the market. This is not WordPress, you don't "add the SEO module" to your pages. While I agree that there could be some additional "defaults" shipped with Tridion, the whole reason why you want Tridion is that you control what it does, in every little detail, you control absolutely everything about your page, and don't trust that some third-party tool will know better than you how to control your website.

I know this puts me in a conflict with the drag-and-droppers out there, who want to be able to drag-and-drop everything and their mother into a page, without really thinking of consequences. I'll give you the consequences at a later post...

Monday, October 15, 2012

Validating content on Save - Part 2 now available

The much awaited 2nd part of the "Validating content on save" series is now online, thanks to Robert Curlette for taking over this epic effort.

Monday, October 01, 2012


As hinted on my last post - and as made public by the Toronto User Group announcement a couple of weeks ago - I have, as of today, left the wonderful world of Professional Services and started a new challenge on the also wonderful world of Product Management.

I have been a consultant for almost all of my Professional career (15 of 17 years), and have pretty much covered many of the possible ways of building (in no particular order) email servers, firewalls, Windows domains, user directories (pre- and post-LDAP), TCP/IP addressing strategies, intranets, extranets, internet, collaboration servers, application servers, transformation services, open source, closed source, free, expensive, sgml, html (2,3,4 & 5), wml, xml, xhtml, VB, VBA, VBScript, C, C++, Informix 4gl, Clipper, PL/SQL, xslt, collaboration strategies, workflow processes, automation - from factory to work processes, so many integration frameworks, c#, java, php, javascript, data management (big and small data), structured and unstructured data, search engines, recommendation engines, monitoring engines, migration tools, social media, rss, odata, oauth, unix servers, websphere, weblogic, tomcat, jboss, iis, apache, wcf, wwf, xaml, saml, browser debugging tools, memory debugging tools, network debugging tools, and so much more, and always - throughout all these years - kept my customer first mantra. Customer is always right - except when the customer is wrong, in which case it is my duty to point this out to the customer, so that the customer may be right.

This served me well in the past, and I am counting on this instinct to serve me even better in the future. I am extremely happy about having made this move, and being able to influence the future direction of SDL software - Tridion in particular - while keeping my customers first.

I'll be posting regularly on how this transition goes, and certainly about all the new & exciting stuff we will be building at SDL!

See you all on the other side!

Tuesday, September 18, 2012

Discontinuing series

The promised series on how to Validate Content on save will have to be put on hold, due to some decisions I took recently.

Anyway, the good news is that I passed on the content I had already developed for that series to another member of our great community, and I am sure he will post the remaining blogs on how to validate content with Anguilla on his blog sometime soon.

The other even better news is that I will be moving on to a more product-centric position within SDL CMT (Content Management Technologies) and really looking forward to it. More to be announced soon.

Tuesday, July 17, 2012

Validating content on Save - Part 1 of many

Recently I had to do a project where we are validating quite some content options whenever the editors decide their work is done. This got me thinking about sharing some of these experiences. This post is the first of a few that I have lined up on this subject, and where I try to cover the available options for content validation from the simple (and cheap) ones to the very complex and over-engineered.

For (many) years, the solution to the eternal "how do I validate content" question with Tridion has been a combination of making fields mandatory and using the Event System (OnComponentSavePre anyone?).
Recently I had to take a different approach to this, since Tridion 2011 brings all this amazing extensibility framework (codenamed Anguilla) that allows to do whatever we want with our content, right? While this is true, the correct answer comes in many shades of gray, and the biggest obstacle on creating a great solution for validating content for your editors is the learning curve.

Let’s think about how we can do this, by taking a very simple example, then growing it out to bigger things. In the first scenario we're covering in this series of posts, we will focus on how to validate that a field named "Title" starts with a capital letter, and we'll do this using 3 different approaches:
  • Schema restrictions
  • Event System
  • CME Command Extension
Using A Schema Restriction As described in LiveContent, you can apply XSD restrictions to simple Tridion Web Schema fields, so we could change the field definition to be something like this:
<xsd:element maxoccurs="1" minoccurs="1" name="Title">
            <tcm:extensionxml xmlns:tcm="http://www.tridion.com/ContentManager/5.0"></tcm:extensionxml>
        <xsd:restriction base="xsd:string">
            <xsd:pattern value="[A-Z][A-Za-z0-9_ ]*"></xsd:pattern>

This will now force our field to start with an upper case letter, and Tridion will enforce the rule.

 If I now try to save my content, Tridion will let me know I don’t understand what I’m doing:

And since I won’t understand the error message either, this becomes more complex than what we can handle with simple schema restrictions…
There are other simple scenarios, particularly with number fields, that Tridion handles quite gracefully (by not allowing the editor to type a number higher than specified in "xsd:maxInclusive" for instance), or limiting the maximum number of characters you can type in a field. However, fairly quickly we fall into a domain where business logic is required to validate fields (common examples are Start and End Dates for events, where you depend on 2 fields to provide the correct validation).

So this was the "cheap" content validation: schema restrictions.

Let’s go now to the 2nd option, using the Event System.

Taking the same example from above (first character must be upper case) we could take one of 2 approaches: Let the user know that the first letter must be upper case, or automatically changing it. Which approach you take depends on your organization’s culture. In some companies it is OK to have the system take decisions for you, while other organizations need to give the editorial team full control about any content that gets created. Let's build an event system to deal with the second approach (letting the editors know about the errors of their ways):

Step 1: create an Event Class Library with Visual Studio.

Add some references from [Tridion-Home]\bin\client

Then let’s write some code to validate if your first character is upper case, and notify the editor if that’s not the case.
using System;
using System.Collections.Generic;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.ContentManagement.Fields;
using Tridion.ContentManager.Extensibility;
using Tridion.ContentManager.Extensibility.Events;

namespace ValidateTitleFieldUpperCaseFirstLetter
    public class Validate : TcmExtension, IDisposable
        private readonly List<EventSubscription> _subscriptions = new List<Eventsubscription>();

        public Validate()

        private void Subscribe()
            EventSubscription subscription =
                EventSystem.Subscribe<Component, SaveEventArgs>(ValidateFirstLetterIsUpperCase, EventPhases.Initiated);

        private void ValidateFirstLetterIsUpperCase(Component component, SaveEventArgs args, EventPhases phases)
            if (component.Schema.Title != "Article") return;
            if (component.ComponentType != ComponentType.Normal) return;
            ItemFields fields = new ItemFields(component.Content, component.Schema);
            SingleLineTextField titleField = (SingleLineTextField)fields["Title"];
            if(titleField.Values.Count == 0)
                // Tridion should take care of this, but just in case someone changed the field to optional
                throw new Exception("Title field is mandatory.");
            string fieldContent = titleField.Value;
                throw new Exception("The first letter of the Title field must be a Capital letter.");

        public void Dispose()
            foreach (EventSubscription subscription in _subscriptions)

Now let’s build our code and tell Tridion to execute it (add a line similar to this to Tridion.ContentManager.Config under "<extensions>"

<add assemblyFileName="D:\Tridion 2011\PathToYourDll\ValidateTitleFieldUpperCaseFirstLetter.dll" />

Restart Tridion (COM+ and Service Host) and let’s see what it does.

So, it’s a nice improvement from the previous message. Cost of development? Well, it took me about 20 minutes to write it and deploy it (fair enough, it’s far from ready, with things that you shouldn’t see in production like "if (component.Schema.Title != "Article") return;"), but you get the picture.

You could also just be slightly smart about it and outline this requirement in the field’s description:
But this is too specific to this use case, and it’s a simple one after all.

Next (within a few days, I promise) we will start looking at how we could do this with Anguilla.

Tuesday, June 05, 2012

The surprising difference of a good interface

Something happened to me in the past few days that got me thinking about User Interfaces and how important they really are.

Last week was my birthday (thank you) and one of the most surprising gifts I received was a Logitech Driving Force GT Steering Wheel (as pictured above). I found it quite amusing, but frankly assumed it would be condemned to stay hidden away somewhere in my apartment: the last time I had played GT 5 was over a year ago, and though I think the game is brilliantly done, I had lost appetite for it.

Nevertheless, I decided I had to try this new way to play the game, with a more realistic interface.

And it's been... quite... amazing!

I just can't believe how much more real the game feels, how much the feedback received on the wheel changes the whole experience, how much more fun - and even scary - the same game feels. The exact same game that had been abandoned when I was just level 15. Since Friday night I made it to level 25. In other words, I spent about the same time playing since last Friday than I had in the previous ~1.5 years since I bought the game.

I tend to think I'm a person that looks at engineering for engineering's sake, and discard presentation tricks, and tend to think of the beauty of a system by its inner workings, not by how it is presented. But here is proof to the contrary: I got instantly re-addicted to a game I had discarded. Granted, I kept respect for the game, it is brilliantly executed - but never assumed that a better interface would get me so much back into it.

Being who I am, of course I started doing analogies to our latest UI update, the product formerly known as SiteEdit. In the end, the UI update is nothing more than a Steering Wheel. The core product has not changed, you still have to do the exact same tasks, in the exact same order. A Component Presentation still has a Component and a Component Template. An image still is a multimedia component. A Page is still a collection of Component Presentations with a Page Template. But something about it makes me install it on every server I install - including my playground servers - simply because it is fun.

Some months ago I had to do an impromptu demo to a customer, and started by apologizing for the inevitable errors that a test environment will always contain. It is after all my testing playground and it is supposed to be broken. 10 minutes into the demo, the customer asked to see SiteEdit - and I replied that I wouldn't have SiteEdit on my test server - it's a test server, not something I'd use for content creation!

Less than a year later, my servers are still my testing playground, they're still utterly broken in many ways that make then unsuitable for demos. But the new shiny Tridion UI is there. And I still don't use those servers to create content.

So, what changed?

Just like adding a Steering wheel to my GT 5 experience, Tridion UI just makes it more fun, as if you're somehow more connected to the system, experiencing a more natural way to interact with it.

Here's looking forward to more features being added to what is simply put a brilliant interface! (I mean the UI, not the steering wheel)

Thursday, March 22, 2012

Uniquely positioned for Localization?

As you probably know, SDL Tridion's really great strength (other than a smashing interface and great tools of course), is Blueprinting.

I'm not going to talk about Tridion BluePrinting here, but rather on what it allows us to do as web content manager implementers. If you're searching for BluePrinting information, check here and here.

(Side note: BluePrinting is such a strong name when it comes to localization that even some of our competition is using it.)

As part of my job as evangelist/guru/community builder/promoter/trainer/debugger/fireman I sometimes get to lecture template developers in regards to best practices when going global, and I always find it curious how certain things that are so obvious to me feel so out-of-this-world to others. This post was triggered by finding a template with something along the lines of:

<div class="productprice">@@Labels.Price@@: $@@Fields.Price@@</div>

One might thing that it is great that the developer thought of using labels for the Price label, meaning I can easily translate this tag. But the template developer also left a '$' sign in the template, screwing up my chances to sell this product in Europe (or Canada, Mexico, Brazil, etc).

So when asked to fix this, the developer would probably do something like:

<div class="productprice"> @@Labels.Price@@: @@Labels.CurrencySymbol@@ @@Fields.Price@@</div>

Great, right? Pretty easy to deal with, right?


Some cultures will display the currency symbol after the amount, not before.

Another typical example I encounter is the myth that Latin America can be grouped into one large "Spanish" chunk, usually forgetting Brazil, and mostly forgetting culture - if not language. To be honest, yes, Argentinians will have no problem reading your site's Mexican version of their language. But they will also be rather quickly fed up of it (especially because your site's domain does end with .com.ar) and buy your product from that other site. You know, the one that knows what a frutilla is.

The sample above applies equally to French, Portuguese, English, Arabic, etc.

And then we get past language and into true localization.

I had the privilege of watching Mike Walsh's presentation "Yesterday the World changed - now it's your turn" during SDL Innovate in Santa Clara, and this was one of the best examples of true localization.
Why is the bottle on top of that car?

This will be incredibly obvious to a few million people, and extremely obscure to every one else. So why would your content in French interest both Canadian and Belgian visitors?

All this to say that I am getting to the conclusion that I am surrounded by people that understand these fine details of localization because of their own background. Half of the team I work with has lived in at least 3 different countries (really lived in, not just passing by doing a consulting gig), speaks 2 or more languages regularly and browse the web in multiple languages.

My own web content consumption is multilingual/localized. Of all the sites I regularly read:
  • 1 is Spanish
  • 3-4 are Portuguese
  • 1 is Dutch
  • 2 are French
The rest is either simplified English (you know, the non-native, non-localized version of it) or North American.

So, I guess I found the key. If you want to understand globalization & localization - go live somewhere else.

Thursday, March 08, 2012

SDL Innovate - what a blast!

This year's SDL Innovate conference was certainly one of the highlights of my career with SDL. What a great event we had (leave a comment if you agree!) with many interesting sessions, partner demos, guest speakers, and more importantly, good networking.

As promised in my previous post, here's a run-through of my short session on Tuesday afternoon about Targeting and your content.

The topic of the session I was involved in was "SDL Tridion Roadmap and Community Panel", with our VP of Products Ian Truscott getting us started by sharing the release plan for 2012, with the highlights being a new Tridion user interface (previously known as SiteEdit) for content editors, Enterprise Content Libraries for external systems integration and a new Tridion release towards the end of the year - more on these topics at a later date sometime soon.

While we were preparing for this session, me & Frank decided that rather than discuss what's coming up in products we should talk about what our current products already do but not all customers are doing:
  • Social
  • Targeting
  • Mobile
Here's what I had to say about Targeting.

We've been targeting (and targeted) for a long time
Ever since humans started trading, targeting has been done by everyone. From the butcher that tries to sell you his "best" meats, to the baker, there has always been an element of targeting, so it is certainly not a surprise that we do it on the web.

Targeting is always about getting something from you
We are always trying to sell something - content you're interested in (increase my views!), a visit to the closest store, a product, a return visit to the site. The objective of targeting is always to convince you of something you may be interested in.

There's many ways to target visitors
Almost everything on the web today involves targeting of some sort. We can always think about good old Amazon.com as the grandfather of targeting, and one of the things about Amazon is that they don't even try to be subtle about it - You bought this before, so you're likely to want this now.

Other sites also target you, but in subtler ways - LinkedIn regularly shows me job ads for jobs with the same Job Title I currently have, and google will show you a map in the search results page if you search for "walmart" or "starbucks" - all of that is targeting.

So, let's take a tour of how Targeting evolved in the past 10 years
10 years ago we could already target visitors (yes, Tridion had it!) based on 2 types of information we could retrieve from you:
  • Data you would tells about you on a registration form (Explicit)
  • Your click behavior browsing our site (Implicit)
We could do quite a lot of targeting based on this data, but the only data source we had for this behavior was our own website.

Fast forward 5 years to 2007
By 2007 most enterprises had finally sorted out their back end integrations, and we could start merging information from your "real" life and your virtual life. I suddenly knew that you were now at my site, and just had bought 5 cans of beer on one of our supermarkets this afternoon, and that perhaps you were trying to get some more delivered (long live loyalty cards!).

So now my data sources about a visitor were certainly growing - but still mostly confined to my own space.

Targeting in 2012
Now we have SO much information about visitors that the challenge becomes a "data management" challenge rather than an operational one. We (can) have access to so much data - your twitter streams, your facebook profile (and your friends'), your LinkedIn profile, your stack overflow, your blog, and this coupled with Social Intelligence tools can give us such a fine grained view of who you are, where you live, which products you like (and dislike) that the visitor becomes its own marketing segment.

What does it mean to content?
The biggest challenge for content creation teams is that with targeting comes content explosion. We have to start having a LOT more content than we ever did before if we want to cater to all possible variations of a user's preferences, history, Twitter opinions, frequent flier program, job title, etc, and a strong usage of taxonomy for your content is definitely recommended.

Key take away points:
  • More data than ever before about your visitors - and this will only increase
  • Customers want targeting. They want you to know who they are
  • Your content model must evolve from being page-centric to being customer-centric
  • Tools help execute - but cannot define your strategy

Monday, March 05, 2012

More targeting

Wow, this has been a great event so far - and we're not even half way through it.

The message seems to be clear - be relevant, be relevant, be relevant.

My session tomorrow is 100% about targeting. I have made a promise (mostly to myself, definitely not to our Sales team) to not mention a single product name, since I want to focus on the impact on your organization for content targeting instead of what product X does better than Y, and it seems that in every session so far content relevancy has been high up in the list of questions and topics.

Tahzoo's Brad Heidemann, during his presentation of how KeyBank is implementing Targeting for the 21st century, redirected some of the questions towards "my" session tomorrow so I can definitely start feeling the pressure.

[edits some slides]

Time to go back to the floor and listen to some more of the great stuff coming out of SDL Innovate - be sure to follow #sdlinnovate for the latest updates.

Sunday, March 04, 2012


This week I'm at SDL Innovate as part of the WCM Roadmap session with fellow Tridionauts Julian Wraith, Ian Truscott, Frank van Puffelen and Tridion MVP Chris Summers, and will be talking about how Targeting and providing relevant content to your visitors is not a scary task anymore - as long as you know what you're doing, and can cope with the impact on how you develop content.

More importantly, I will be trying to drive the message that targeting your audience is not something that relies only on technology, and that simply by the fact of using a CMS like Tridion you already have the ability to make your content relevant to your visitors - as long as you have a strategy.

Stay tuned, I'll post my presentation and notes here after delivering it on Tuesday afternoon.

Saturday, February 11, 2012


I've spent the last week in SDL's office in Amsterdam with some of the Tridion masters (including Alvin Reyes and Mihai Cadariu) for some knowledge transfer from R&D regarding our soon-to-be-launched re-vamped, re-thought, re-designed and re-super-improved SiteEdit 2012.

As typically happens in this type of Knowledge Transfer, the information flow always goes both ways - we learn from R&D on what the tool is expected to do while showing back to R&D how we expect it to behave under the blueprint abuse that we constantly put Tridion through.

And while it was clear that the tool is still in development (a couple of buttons were not enabled yet on the build we used) it was also clear that what is in place really works amazingly well.

I really don't even know where to start when it comes to SiteEdit, there's just so much being added and/or modified that it's hard to start.

So I'll start with the simple improvements I've seen.
  1. Defining Page Types (a prototype from which you can create a new page) is as simple as checking a box on _any_ existing page.
  2. Adding an image to Tridion's "content library" is as simple as dragging & dropping it into your existing library
  3. SessionPreview architecture shows changes to pages dynamically without the need to republish the page or any of component presentations (and avoiding any publishing queue bottleneck).
  4. The whole wording of this interface is much user-friendlier than Tridion's language in general, which tends to be very technical - Content instead of Components, "Edit everywhere" instead of "Edit parent"
  5. Ability to associate component templates with page templates - so that users will only see the options that make sense to use in any given page - and present these to the user as "Content Types"
Well, there's just so much! So, why don't I shut up and let some pictures speak a few thousand words?

Editing a "shared" component:
Selecting a page type for a new page:
 Editing Content:
Selecting an image from the library:

Absolutely amazing and surprisingly stable and fast. Can't wait for it to come out.

Monday, January 30, 2012

The content blues

Editors are very hard to keep happy. From where I stand, most of my direct interaction points with our customers are usually System Administrators, Architects and/or Developers.

These people are "easy" to satisfy when you're dealing with a system with so many Enterprise features and extension points as SDL Tridion. The questions or scenarios I get asked to expand on will typically boil down to either something that Tridion does already, or something that we can extend Tridion to do.

I have however found the hardest Tridion user of all. The content editor. And that person, my friends, is none other than myself.

Since August last year I started publishing (with Bart Koopman's help) a weekly review of all activities that are in anyway Tridion-Community-related. The schema for this content, as you may expect if you look into it, is rather simple and made up of a few RTF fields alternated with some (limited) taxonomy and multimedia links to the images displayed.

So far nothing abnormal. Content creation is relatively painless, since I have my RTF and I put in it whatever I want.

The problem is when I start thinking about what to do now that I beat my own expectations and this weekly review is becoming an actual important starting point of every week, and there's quite a lot of data in it begging to be mined. To start with, I will need to start archiving this data in an easy to browse archive. Having all content together will eventually become unwieldy (some may argue it's already the case).

The 2nd problem is my own demands on my own data. I want, for instance, to rapidly know which week was the busiest week (week with the highest number of links to blogposts/content). Well, I can't, because I'm using RTF.

I also wanted to do a "Top 10" for the great people in the community that contribute so much every week. Again - almost impossible to do other than counting manually, since the content is in RTF.

Next, I may want to dig into all posts that relate to Event System. Or Deployer Extensions. Or Storage Extensions. Or WCF. You catch my drift, right?

What's the solution?

The solution is in making the Editor's life a living hell. Instead of the ~15 minutes it takes me now to create a weekly review (mostly it's Bart), it will probably turn into an hour long exercise at least. Every entry mentioned in there should actually be its own component, and this component should be classified by Author, Publish/Creation Date, Topic(s), Source. I would normally have no problems presenting to my customer the fact that if you want your content to be rich, YOU need to enrich it.

But it hurts when the customer is me...

Thursday, January 12, 2012

It's the little things: Creating a page breadcrumb in Tridion

Your mileage may vary, but in most cases (> 90%) pages published from Tridion will include a breadcrumb that is linked to the page's location in the site (i.e., Structure Groups).

Typically I see this breadcrumb being generated in the front-end from the Sitemap, which is not a very expensive operation but still a very silly approach. If an editor creates a page in a given Structure Group and publishes it, we already know the page's location at publish time, so why would we waste some CPU cycles on the front-end determining this?

Since I had to write this Building Block just now I thought I could share it with you.

using System.Text.RegularExpressions;
using System.Xml;
using Tridion.ContentManager;
using Tridion.ContentManager.CommunicationManagement;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.Templating.Assembly;

namespace TridionTemplates
    public class GetPageBreadcrumb : ITemplate
        private const string _separator = " » ";
        private const string RegexPattern = @"^[\d]* ";
        private const string indexPagePattern = "index";
        private readonly Regex _regex = new Regex(RegexPattern, RegexOptions.None);

        public void Transform(Engine engine, Package package)
            TemplatingLogger log = TemplatingLogger.GetLogger(GetType());
            if (package.GetByName(Package.PageName) == null)
                log.Info("Do not use this template building block in Component Templates");

            Page page = (Page)engine.GetObject(package.GetByName(Package.PageName));

            string output = StripNumbersFromTitle(page.OrganizationalItem.Title);
            foreach (OrganizationalItem parent in page.OrganizationalItem.GetAncestors())
                output = GetLinkToSgIndexPage((StructureGroup)parent, engine.GetSession()) + _separator + output;

            package.PushItem("breadcrumb", package.CreateStringItem(ContentType.Html, output));

        private string StripNumbersFromTitle(string title)
            return Regex.Replace(title, RegexPattern, string.Empty);

        private string GetLinkToSgIndexPage(StructureGroup sg, Session session)
            OrganizationalItemItemsFilter filter = new OrganizationalItemItemsFilter(session);
            filter.ItemTypes = new[] { ItemType.Page };
            string title = StripNumbersFromTitle(sg.Title);
            string pageLinkFormat = "<a tridion:href=\"{0}\">{1}</a>";
            string result = null;
            foreach (XmlElement page in sg.GetListItems(filter).ChildNodes)
                if (page.Attributes["Title"].Value.ToLower().Contains(indexPagePattern))
                    result = string.Format(pageLinkFormat, page.Attributes["ID"].Value, title);
            if (string.IsNullOrEmpty(result))
                result = title;
            return result;

Yes, it does quite a lot more than just create a breadcrumb, I'll leave it up to you figure that out :)

PS - I am using OrganizationalItem.GetAncestors() in this code, which means it will only work with SDL Tridion 2011 SP1.