Choosing the right method for a custom traversal

We have been working lately on a package called collective.liveblog; it's a Dexterity-based content type to describe a blog post which is intended to provide a rolling textual coverage of an ongoing event.

You can see it working in the coverage of the impeachment of the President of Brazil and the Olympic torch relay in Brasília.

As you can see, the post is updated frequently and those updates are stored in annotations in the Liveblog object with code I stole from Products.Poi.

It has been working very well and now we need to enhance it by allowing traversing to individual updates to display them as separate content that can be used in social media the way others, like El País from Spain, do.

so, basically, the idea is to traverse to the posts using it's timestamp, for instance:

@rodfersou has been working on a pull request to implement this, but I think the traversal is not registered the way we need as we are currently registering from the custom view and not from the Liveblog object itself, so now we don't have what we want but:

Any hints on how to solve this are welcomed; this is the first time I have to deal with a custom traversal and the documentation doesn't contain any suitable example.

I suppose you have a view defined for the object
In this case publishTraverse could be implemented on this default view.

Or, if you do not like this, you can implement an IBrowserPublisher adapter for the my-liveblog type. This is pretty straight forward: if there are items left in request['TraversalRequestNameStack'] make a copy of it (it will be consumed) and delegate to do the usal lookup, so the normal views are coming up if this is possible. If nothing was looked up, do your own lookup from the copied TraversalStack and in case of a match delegate to the special view as in the PR and return it.

Btw.: Good read on how publishing works is the code itself at

@jensens thank you for your input!

I tried to follow your suggestions, but now I got a problem with image resolveuid.. the way I added the adapter make all traverse for my object fall into my view

Obviously I did something wrong, any help would be appreciated!

thanks for your help; we ended up registering it using IPublishTraverse:

we did it this way because we want to cache the view render on intermediate proxies.

Let's resume this old post! I'm now in the same situation.

I'd like to achieve your first goal:

Where my-liveblog is an object with a default view (called "view"), and timestamp-1 is a custom string that I want to append in the URL, read it in the default view and do some things related to it.

I followed the documentation too, but i can't achieve it.

I implemented IPublishTraverse, added publishTraverse method, etc but when I call the only thing that I get is a 404.

If I call it works like a charm.

Am I missing something, or that's the correct way it should work because I'm customizing the traversal of the view and not the object's one?

If I understand correctly, @hvelarde you give up the initial idea and use the /view/ approach. Just for caching reasons, or because you didn't find any solution?

Your observation is correct and consistent with my own observations while working on traversal in xmldirector.plonecore

I could not find a solution for by-passing the view name in the URL - at least in my case it is a feature that I can apply multiple views implementing different behaviors on the content specified by the traversal subpath.

I assume that you have implemented IPublishTraverse on the view (as in the example). This does not work as the default view is determined by a special mechanism (--> IPublishTraverse.browserDefault) only at the end of the traversal path. In your case, there is still a path component (--> timestamp-1) when the traversal has located my-liveblog and therefore, the default view is not activated.

It is not trivial to achieve what you want: your timestamp-1 path suffix competes with the ids of content items and the names of explicit views. In any case, the disambiguation logic (maybe via IPublishTraverse, an AccessRule or a __bobo_traverse__ hook) must be activated on your my-liveblog object, not on its default view.

Thanks for your suggestion. I'll try it out.

Otherwise I can use an intermediate "/view/" path like Andreas and Hector.

Plone Foundation Code of Conduct