Last modified: May 05, 2025 By Alexander Williams

Plone Traversal System Guide

Plone's traversal system maps URLs to content and views. It's a core feature that makes Plone flexible. This guide explains how to customize it.

Understanding Plone Traversal

Traversal is how Plone finds content by URL. When you request /folder/document, Plone traverses from root to folder to document.

The system uses adapters and views to handle requests. You can hook into this process to create custom paths.

For more on Plone's architecture, see our Plone Fundamentals guide.

Basic View Registration

First, let's register a simple browser view. Views are Python classes that render content.


# In configure.zcml
<browser:page
    name="my-view"
    for="*"
    class=".views.MyView"
    template="mytemplate.pt"
    permission="zope2.View"
    />

This registers a view available at context/@@my-view. The for="*" means it works on any content type.

Custom Traversal with Python

For more control, implement IPublishTraverse. This lets you handle path segments directly.


from zope.interface import implementer
from zope.publisher.interfaces import IPublishTraverse

@implementer(IPublishTraverse)
class MyTraverser:
    def __init__(self, context, request):
        self.context = context
        self.request = request
    
    def publishTraverse(self, request, name):
        # Handle custom path segments here
        if name == 'special':
            return SpecialContent()
        return self.context

Register this in ZCML with an adapter. Now /context/special will use your code.

Creating RESTful Endpoints

Traversal is perfect for REST APIs. Here's a simple JSON endpoint:


from plone.restapi.services import Service
from zope.interface import implementer
from zope.publisher.interfaces import IPublishTraverse

@implementer(IPublishTraverse)
class MyAPI(Service):
    def __init__(self, context, request):
        super().__init__(context, request)
        self.params = []
    
    def publishTraverse(self, request, name):
        self.params.append(name)
        return self
    
    def reply(self):
        return {
            "context": self.context.title,
            "params": self.params
        }

Access this at /context/@myapi/path/parts. It will return JSON with the path parts.

View Methods as Path Segments

You can expose view methods as path segments. This creates clean URLs.


class ReportView(BrowserView):
    def __call__(self):
        if len(self.request.traversed_subpath) > 0:
            return getattr(self, self.request.traversed_subpath[0])()
        return self.index()
    
    def summary(self):
        return "Summary report"
    
    def details(self):
        return "Detailed report"

Now /context/@@report/summary shows the summary. /context/@@report/details shows details.

Advanced: Custom Content Providers

For reusable components, use content providers. They work well with traversal.

First, register a provider in ZCML:


<browser:provider
    name="my.provider"
    for="*"
    class=".providers.MyProvider"
    permission="zope2.View"
    />

Then call it in templates with context/@@my.provider. Learn more in our View Components Guide.

Security Considerations

Always check permissions in custom traversers. Use checkPermission() from zope.security.

For complex permission needs, see our Permissions Guide.

Debugging Traversal Issues

Common problems include:

  • Missing ZCML registrations
  • Incorrect interface implementations
  • Permission errors

Use Plone's debug mode to test traversal. Add ?debug=true to URLs.

Conclusion

Plone's traversal system is powerful. You can create custom URLs, REST APIs, and dynamic views.

Start simple with basic views. Then explore IPublishTraverse for advanced routing.

Remember to always consider security. Test your custom paths thoroughly.

For more on Plone development, check our Add-on Guide.